diff --git a/credits.toml b/credits.toml index 91585cc..d02252c 100644 --- a/credits.toml +++ b/credits.toml @@ -158,3 +158,9 @@ name = "Fantozzi" [[people.credits]] credit = "Fantozzi's Footsteps (Grass/Sand & Stone)" link = "https://opengameart.org/content/fantozzis-footsteps-grasssand-stone" + +[[people]] +name = "TobiasM" +[[people.credits]] +credit = "Blood splat" +link = "https://opengameart.org/content/blood-splat" diff --git a/godot/raw_assets/blood_splat.png b/godot/raw_assets/blood_splat.png new file mode 100644 index 0000000..ac79c43 Binary files /dev/null and b/godot/raw_assets/blood_splat.png differ diff --git a/godot/raw_assets/blood_splat.png.import b/godot/raw_assets/blood_splat.png.import new file mode 100644 index 0000000..5741aa2 --- /dev/null +++ b/godot/raw_assets/blood_splat.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cnahou6bg32pu" +path="res://.godot/imported/blood_splat.png-2bef76897d4f45e457d6e9899a1358ed.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://raw_assets/blood_splat.png" +dest_files=["res://.godot/imported/blood_splat.png-2bef76897d4f45e457d6e9899a1358ed.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/uastc_level=0 +compress/rdo_quality_loss=0.0 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/channel_remap/red=0 +process/channel_remap/green=1 +process/channel_remap/blue=2 +process/channel_remap/alpha=3 +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/godot/scenes/player/blood_decal.tscn b/godot/scenes/player/blood_decal.tscn new file mode 100644 index 0000000..4af0a27 --- /dev/null +++ b/godot/scenes/player/blood_decal.tscn @@ -0,0 +1,9 @@ +[gd_scene format=3 uid="uid://c1sc6yl56mi0s"] + +[ext_resource type="Texture2D" uid="uid://cnahou6bg32pu" path="res://raw_assets/blood_splat.png" id="1_1rw23"] + +[node name="bullet_hole_decal" type="Node3D" unique_id=18163478] + +[node name="decal" type="Decal" parent="." unique_id=1515351623] +size = Vector3(1, 1, 1) +texture_albedo = ExtResource("1_1rw23") diff --git a/godot/scenes/player/effects.tscn b/godot/scenes/player/effects.tscn index 1326f64..79c61dc 100644 --- a/godot/scenes/player/effects.tscn +++ b/godot/scenes/player/effects.tscn @@ -11,6 +11,7 @@ [ext_resource type="AudioStream" uid="uid://dpafq3gxer7qf" path="res://raw_assets/sfx/footsteps_congusbongus/tile/0.ogg" id="8_7a25g"] [ext_resource type="AudioStream" uid="uid://fn5olcnrb1jn" path="res://raw_assets/sfx/footsteps_congusbongus/water/2.ogg" id="9_k2vl2"] [ext_resource type="AudioStream" uid="uid://br64dea537kkw" path="res://raw_assets/sfx/footsteps_congusbongus/wood/0.ogg" id="10_x30cj"] +[ext_resource type="PackedScene" uid="uid://c1sc6yl56mi0s" path="res://scenes/player/blood_decal.tscn" id="11_otyku"] [sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_1cgct"] particle_flag_align_y = true @@ -57,6 +58,7 @@ footstep_sounds = Dictionary[String, AudioStream]({ "Wood": ExtResource("10_x30cj") }) walk_sfx_cd = 0.5 +blood_decal = ExtResource("11_otyku") [node name="splorch" type="GPUParticles3D" parent="." unique_id=986677517] emitting = false diff --git a/rust/src/player/ball.rs b/rust/src/player/ball.rs index e61f4ea..bada67e 100644 --- a/rust/src/player/ball.rs +++ b/rust/src/player/ball.rs @@ -94,10 +94,10 @@ impl Ball { #[godot_dyn] impl Shootable for Ball { - fn on_shoot(&mut self, _: DamageSource, damage: i32, dir: Vector3) { + fn on_shoot(&mut self, _: DamageSource, damage: i32, delta: Vector3) { let prev_velocity = self.base().get_linear_velocity(); let force = damage as f32 / 10.; self.base_mut() - .set_linear_velocity(prev_velocity + dir * force); + .set_linear_velocity(prev_velocity + delta.normalized() * force); } } diff --git a/rust/src/player/effects.rs b/rust/src/player/effects.rs index 9512c38..da90898 100644 --- a/rust/src/player/effects.rs +++ b/rust/src/player/effects.rs @@ -1,10 +1,12 @@ -use std::collections::HashMap; +use std::{collections::HashMap, f32::consts::PI}; use godot::{ - classes::{AudioStream, AudioStreamPlayer3D, GpuParticles3D}, + classes::{AudioStream, AudioStreamPlayer3D, GpuParticles3D, RandomNumberGenerator}, prelude::*, }; +use crate::{game::Game, util::shotgun_ray}; + #[derive(Debug, Clone, Copy, GodotConvert, Export, Var, Default, PartialEq, PartialOrd, Eq)] #[godot(via = GString)] pub enum FootstepKind { @@ -36,6 +38,10 @@ pub struct PlayerEffects { footstep_sounds: Dictionary>>, #[export] walk_sfx_cd: f64, + #[export] + blood_decal: Option>, + + rng: Gd, walk_sfx_cd_remaining: f64, @@ -93,4 +99,44 @@ impl PlayerEffects { sfx.set_stream(&sound); } } + + pub fn shoot_blood(&mut self, delta: Vector3, force: f32) { + self.run_deferred(move |s| { + if let Some(mut game) = Game::singleton() + && let Some(map) = &mut game.bind_mut().current_map + && let Some(prefab) = &s.blood_decal + { + let results = shotgun_ray( + s.base().get_global_position(), + s.base().get_global_position() + delta, + s.base().get_basis().col_c(), + &s.base().get_world_3d(), + &Array::new(), + (20. / delta.length()) as u8, + (((PI / 4.) * force) / delta.length()).min(PI / 2.), + 10. + delta.length() / 3., + None, + ); + + let mut decal_results = Vec::new(); + for _ in 0..(force * 5.) as usize { + if let Some(result) = results + .get(s.rng.randi_range(0, results.len() as i32 - 1) as usize) + .cloned() + { + decal_results.push(result); + } + } + godot_print!("{:?}", decal_results); + + for result in decal_results { + let mut decal = prefab.instantiate_as::(); + map.add_child(&decal); + decal.set_global_position(result.position); + let quat = Quaternion::from_rotation_arc(Vector3::UP, result.normal); + decal.set_global_rotation(quat.get_euler()); + } + } + }); + } } diff --git a/rust/src/player/local_player.rs b/rust/src/player/local_player.rs index 915d80f..77ccbe5 100644 --- a/rust/src/player/local_player.rs +++ b/rust/src/player/local_player.rs @@ -939,7 +939,12 @@ impl LocalPlayer { #[godot_dyn] impl Shootable for LocalPlayer { - fn on_shoot(&mut self, source: DamageSource, damage: i32, _: Vector3) { + fn on_shoot(&mut self, source: DamageSource, damage: i32, delta: Vector3) { + if self.can_take_damage(&source) + && let Some(fx) = &mut self.effects + { + fx.bind_mut().shoot_blood(delta, damage as f32 / 100.); + } self.take_damage(source, damage, true); } } diff --git a/rust/src/player/remote_player.rs b/rust/src/player/remote_player.rs index 519d07c..9e97245 100644 --- a/rust/src/player/remote_player.rs +++ b/rust/src/player/remote_player.rs @@ -501,7 +501,12 @@ impl RemotePlayer { #[godot_dyn] impl Shootable for RemotePlayer { - fn on_shoot(&mut self, source: DamageSource, damage: i32, _: Vector3) { + fn on_shoot(&mut self, source: DamageSource, damage: i32, delta: Vector3) { + if self.can_take_damage(&source) + && let Some(fx) = &mut self.effects + { + fx.bind_mut().shoot_blood(delta, damage as f32 / 100.); + } self.take_damage(source, damage, true); } } diff --git a/rust/src/player/weapon.rs b/rust/src/player/weapon.rs index 3850d19..95ed382 100644 --- a/rust/src/player/weapon.rs +++ b/rust/src/player/weapon.rs @@ -104,11 +104,13 @@ impl Weapon for Raygun { }); } - let dir = (to - source.get_global_position()).normalized(); + let beam_dir = (to - source.get_global_position()).normalized(); let beam_end = target .as_ref() .map(|r| r.position) - .unwrap_or(source.get_global_position() + dir * 100.); + .unwrap_or(source.get_global_position() + beam_dir * 100.); + let delta = beam_end - source.get_global_position(); + godot_print!("{}", delta); if let Some(prefab) = &self.bullet_prefab && play_fx @@ -138,7 +140,7 @@ impl Weapon for Raygun { shootable.dyn_bind_mut().on_shoot( DamageSource::Player(player_id), 100, - dir.normalized(), + delta, ); }); }