diff --git a/block_values.lua b/block_values.lua index fbd2674..8ad57fe 100644 --- a/block_values.lua +++ b/block_values.lua @@ -26,7 +26,7 @@ minetest.register_on_mods_loaded(function() RHA = RHA / groups.oddly_breakable_by_hand end if groups.choppy then - RHA = RHA/(5*groups.choppy) + RHA = RHA/(10*groups.choppy) end if groups.flora or groups.grass then RHA = 0 diff --git a/classes/Bullet_ray.lua b/classes/Bullet_ray.lua index 8c7fe78..1f81d1f 100644 --- a/classes/Bullet_ray.lua +++ b/classes/Bullet_ray.lua @@ -12,8 +12,38 @@ local ray = { sharp_to_blunt_conversion_factor = .5, -- 1mmRHA is converted to 1mPA of blunt force blunt_damage_groups = {}, --minetest.deserialize(Guns4d.config.default_blunt_groups), --these are multiplied by blunt_damage sharp_damage_groups = {}, --minetest.deserialize(Guns4d.config.default_sharp_groups), - ITERATION_DISTANCE = .3, - damage = 0 + pass_sounds = { + --[1] will be preferred if present + supersonic = { + sound = "bullet_crack", + max_hear_distance = 3, + pitch = { + min = .6, + max = 1.5 + }, + gain = { + min = .9, --this uses distance instead of randomness + max = .4 + } + }, + subsonic = { + sound = "bullet_whizz", + max_hear_distance = 3, + pitch = { + min = .5, + max = 1.5 + }, + gain = { + min = .3, --this uses distance instead of randomness + max = .9 + } + }, + }, + supersonic_energy = Guns4d.config.minimum_supersonic_energy_assumption, + pass_sound_max_distance = 3, + damage = 0, + energy = 0, + ITERATION_DISTANCE = Guns4d.config.default_penetration_iteration_distance, } --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 @@ -250,48 +280,90 @@ function ray:bullet_hole(pos, normal) Guns4d.effects.spawn_bullet_hole_particle(pos, self.hole_scale, '(bullet_hole_1.png^(bullet_hole_2.png^[opacity:129))') end end +function ray:play_bullet_pass_sounds() + --iteration done, damage applied, find players to apply bullet whizz to + local start_pos = self.init_pos + local played_for = {} + for i = #self.history, 1, -1 do + local v = self.history[i] + for _, player in pairs(minetest.get_connected_players()) do + if (player~=self.player) and not played_for[player] then + local pos = player:get_pos()+vector.new(0,player:get_properties().eye_height,0) + local nearest = Guns4d.nearest_point_on_line(start_pos, v.pos, pos) + if vector.distance(nearest, pos) < self.pass_sound_max_distance then + played_for[player] = true + if self.pass_sounds[1] then + local sound = Guns4d.table.deep_copy(self.pass_sounds[1]) + sound.pos = nearest + Guns4d.play_sounds(self.pass_sounds[1]) + else + --interpolate to find the energy of the shot to determine supersonic or not. + local v1 + if #self.history > i then v1 = v[i+1].energy else v1 = self.init_energy end + local v2 = v.energy + + local ratio = vector.distance(start_pos, nearest)/vector.distance(start_pos, pos) + local energy_at_point = v1+((v2-v1)*(1-ratio)) + + local sound = self.pass_sounds.subsonic + if energy_at_point >= self.supersonic_energy then + sound = self.pass_sounds.supersonic + end + sound = Guns4d.table.deep_copy(sound) + sound.pos = nearest + for _, t in pairs({"gain", "pitch"}) do + if sound[t].min then + sound[t] = sound[t].max+((sound[t].min-sound[t].max)*(vector.distance(nearest, pos)/self.pass_sound_max_distance)) + end + end + Guns4d.play_sounds(sound) + end + end + end + end + start_pos = v.pos + end +end function ray.construct(def) if def.instance then - assert(def.player, "no player") + --these asserts aren't necessary, probably drags down performance a tiny bit. + + --[[assert(def.player, "no player") assert(def.pos, "no position") assert(def.dir, "no direction") assert(def.gun, "no Gun object") assert(def.range, "no range") assert(def.energy, "no energy") - assert(def.energy_dropoff, "no energy dropoff") + assert(def.energy_dropoff, "no energy dropoff")]] --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.") + -- 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.") + --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 + 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 + def.init_energy = 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) def.history = {} + def.init_pos = vector.new(def.pos) --has to be cloned before iteration def:_iterate() + def:play_bullet_pass_sounds() end end Guns4d.bullet_ray = Instantiatable_class:inherit(ray) \ No newline at end of file diff --git a/init.lua b/init.lua index 022af0f..a53882a 100644 --- a/init.lua +++ b/init.lua @@ -22,6 +22,8 @@ Guns4d.config = { default_fov = 80, headshot_damage_factor = 1.75, enable_touchscreen_command_name = "guns4d_enable_touchmode", + minimum_supersonic_energy_assumption = 900, --used to determine the energy of a "supersonic" bullet for bullet whizzing sound effects + default_penetration_iteration_distance = .25, --`["official_content.replace_ads_with_bloom"] = false, --`["official_content.uses_magazines"] = true } @@ -29,7 +31,7 @@ local path = minetest.get_modpath("guns4d") print("file read?") local conf = Settings(path.."/guns4d_settings.conf"):to_table() or {} -local mt_conf = minetest.settings:to_table() +local mt_conf = minetest.settings:to_table() --allow use of MT config for servers that regularly update 4dguns through it's development for i, v in pairs(Guns4d.config) do --Guns4d.config[i] = conf[i] or minetest.settings["guns4d."..i] or Guns4d.config[i] --cant use or because it'd evaluate to false if the setting is alse diff --git a/misc_helpers.lua b/misc_helpers.lua index 794c345..b6f1cfb 100644 --- a/misc_helpers.lua +++ b/misc_helpers.lua @@ -283,4 +283,17 @@ function Guns4d.rltv_point_to_hud(pos, fov, aspect) local y = (pos.y/pos.z)*a6 local z = (pos.z/pos.z)*a11 return {x=x / 2,y=-y / 2} --output needs to be offset by +.5 on both for HUD elements, but this cannot be integrated. +end + +--Code: Elkien3 (CC BY-SA 3.0) +--https://github.com/Elkien3/spriteguns/blob/1c632fe12c35c840d6c0b8307c76d4dfa44d1bd7/init.lua#L76 +function Guns4d.nearest_point_on_line(lineStart, lineEnd, pnt) + local line = vector.subtract(lineEnd, lineStart) + local len = vector.length(line) + line = vector.normalize(line) + + local v = vector.subtract(pnt, lineStart) + local d = vector.dot(v, line) + d = Guns4d.math.clamp(d, 0, len); + return vector.add(lineStart, vector.multiply(line, d)) end \ No newline at end of file diff --git a/play_sound.lua b/play_sound.lua index 8f7ed1a..fdb726a 100644 --- a/play_sound.lua +++ b/play_sound.lua @@ -32,8 +32,10 @@ local sqrt = math.sqrt -- however has the following changed or guns4d specific parameters. -- @field min_hear_distance this is useful if you wish to play a sound which has a "far" sound, such as distant gunshots. incompatible `with to_player` -- @field sounds a @{misc_helpers.weighted_randoms| weighted_randoms table} for randomly selecting sounds. The output will overwrite the `sound` field. --- @field to_player 4dguns changes `to_player` so it only plays positionless audio (as it is only intended for first person audio) +-- @field to_player 4dguns changes `to_player` so it only plays positionless audio (as it is only intended for first person audio). If set to string "from_player" and player present +-- @field player this is so to_player being set to "from_player". It's to be set to the player which fired the weapon. -- @field delay delay the playing of the sound +-- @field has_speed_of_sound = true -- @table guns4d_soundspec local function handle_min_max(tbl) @@ -84,6 +86,7 @@ function Guns4d.play_sounds(soundspecs_list) sound_handles[handle] = {} local handle_object = sound_handles[handle] for i, soundspec in pairs(soundspecs_list) do + if soundspec.to_player == "from_player" then soundspec.to_player = soundspec.player:get_player_name() end --setter of sound may not have access to this info, so add a method to use it. assert(not (soundspec.to_player and soundspec.min_distance), "in argument '"..tostring(i).."' `min_distance` and `to_player` are incompatible parameters.") local sound = soundspec.sound local outval @@ -95,9 +98,9 @@ function Guns4d.play_sounds(soundspecs_list) if type(sound) == "table" then sound = Guns4d.math.weighted_randoms(sound) end - assert(sound, "no sound found") - if not mtul.paths.media_paths[sound..".ogg"] then - minetest.log("error", "no sound by the name `"..mtul.paths.media_paths[sound..".ogg"].."`") + assert(sound, "no sound provided") + if not mtul.paths.media_paths[(sound or "[NIL]")..".ogg"] then + minetest.log("error", "no sound by the name `"..mtul.paths.media_paths[(sound or "[NIL]")..".ogg"].."`") end --print(dump(soundspecs_list), i) if soundspec.to_player then soundspec.pos = nil end diff --git a/sounds/LICENSE ar_charge.ogg.txt b/sounds/ar/LICENSE ar_charge.ogg.txt similarity index 100% rename from sounds/LICENSE ar_charge.ogg.txt rename to sounds/ar/LICENSE ar_charge.ogg.txt diff --git a/sounds/LICENSE ar_firing.ogg.txt b/sounds/ar/LICENSE ar_firing.ogg.txt similarity index 100% rename from sounds/LICENSE ar_firing.ogg.txt rename to sounds/ar/LICENSE ar_firing.ogg.txt diff --git a/sounds/LICENSE ar_firing_far.ogg.txt b/sounds/ar/LICENSE ar_firing_far.ogg.txt similarity index 100% rename from sounds/LICENSE ar_firing_far.ogg.txt rename to sounds/ar/LICENSE ar_firing_far.ogg.txt diff --git a/sounds/LICENSE ar_mag_load.ogg.txt b/sounds/ar/LICENSE ar_mag_load.ogg.txt similarity index 100% rename from sounds/LICENSE ar_mag_load.ogg.txt rename to sounds/ar/LICENSE ar_mag_load.ogg.txt diff --git a/sounds/LICENSE ar_mag_store.ogg.txt b/sounds/ar/LICENSE ar_mag_store.ogg.txt similarity index 100% rename from sounds/LICENSE ar_mag_store.ogg.txt rename to sounds/ar/LICENSE ar_mag_store.ogg.txt diff --git a/sounds/LICENSE ar_mag_unload.ogg.txt b/sounds/ar/LICENSE ar_mag_unload.ogg.txt similarity index 100% rename from sounds/LICENSE ar_mag_unload.ogg.txt rename to sounds/ar/LICENSE ar_mag_unload.ogg.txt diff --git a/sounds/ar_charge.ogg b/sounds/ar/ar_charge.ogg similarity index 100% rename from sounds/ar_charge.ogg rename to sounds/ar/ar_charge.ogg diff --git a/sounds/ar_firing.ogg b/sounds/ar/ar_firing.ogg similarity index 100% rename from sounds/ar_firing.ogg rename to sounds/ar/ar_firing.ogg diff --git a/sounds/ar_firing_far.ogg b/sounds/ar/ar_firing_far.ogg similarity index 100% rename from sounds/ar_firing_far.ogg rename to sounds/ar/ar_firing_far.ogg diff --git a/sounds/ar_mag_load.ogg b/sounds/ar/ar_mag_load.ogg similarity index 100% rename from sounds/ar_mag_load.ogg rename to sounds/ar/ar_mag_load.ogg diff --git a/sounds/ar_mag_store.ogg b/sounds/ar/ar_mag_store.ogg similarity index 100% rename from sounds/ar_mag_store.ogg rename to sounds/ar/ar_mag_store.ogg diff --git a/sounds/ar_mag_unload.ogg b/sounds/ar/ar_mag_unload.ogg similarity index 100% rename from sounds/ar_mag_unload.ogg rename to sounds/ar/ar_mag_unload.ogg diff --git a/sounds/attribution and licensing.txt b/sounds/ar/attribution and licensing.txt similarity index 100% rename from sounds/attribution and licensing.txt rename to sounds/ar/attribution and licensing.txt diff --git a/sounds/elkien/bullet_crack.ogg b/sounds/elkien/bullet_crack.ogg new file mode 100644 index 0000000..fe2ff8b Binary files /dev/null and b/sounds/elkien/bullet_crack.ogg differ diff --git a/sounds/elkien/bullet_whizz.ogg b/sounds/elkien/bullet_whizz.ogg new file mode 100644 index 0000000..7df8512 Binary files /dev/null and b/sounds/elkien/bullet_whizz.ogg differ diff --git a/sounds/elkien/license.txt b/sounds/elkien/license.txt new file mode 100644 index 0000000..763bd4a --- /dev/null +++ b/sounds/elkien/license.txt @@ -0,0 +1,14 @@ +license info is WIP, I borrowed code and textures/sounds from a lot of places so if you find license info that I have forgotten please let me know. + +Code: Elkien3 (CC BY-SA 3.0) +Textures: + binoculars_binoculars.png (from Minetest Game): Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0) Copyright (C) 2017 paramat + rangedweapons_*: bullets unedited, most of the others are edited from the guns from rangedweapons. (cc-by-sa 4.0 davidthecreator) + All others: Elkien3 (CC BY-SA 3.0) +Models: (CC BY-SA 3.0) + Modelers: Elkien3 (Colt Army), Extex (Remington870, Thompson, Pardini), FatalError (CZ, Mini14, Binoculars). + All tweaked and animated by Elkien3 +Sounds: + I renamed some of them and don't remember exactly where each of them came from. + I do know some came from rangedweapons (cc-by-sa 4.0 davidthecreator) + The rest were sourced from youtube that were largely marked royalty free. \ No newline at end of file