diff --git a/asset_dev/props/wall_switch/wall_switch2.blend b/asset_dev/props/wall_switch/wall_switch2.blend
index b88fc25..601c98a 100644
Binary files a/asset_dev/props/wall_switch/wall_switch2.blend and b/asset_dev/props/wall_switch/wall_switch2.blend differ
diff --git a/asset_dev/props/wall_switch/wall_switch2.blend1 b/asset_dev/props/wall_switch/wall_switch2.blend1
index d1b98ba..b88fc25 100644
Binary files a/asset_dev/props/wall_switch/wall_switch2.blend1 and b/asset_dev/props/wall_switch/wall_switch2.blend1 differ
diff --git a/assets/materials/laser_spray.tres b/assets/materials/laser_spray.tres
new file mode 100644
index 0000000..91aa9d0
--- /dev/null
+++ b/assets/materials/laser_spray.tres
@@ -0,0 +1,45 @@
+[gd_resource type="ShaderMaterial" load_steps=9 format=3 uid="uid://c00gndxoepuqh"]
+
+[ext_resource type="Shader" path="res://src/shaders/plasma.gdshader" id="1_fbhuf"]
+
+[sub_resource type="FastNoiseLite" id="FastNoiseLite_dt0d4"]
+
+[sub_resource type="NoiseTexture2D" id="NoiseTexture2D_hx2kx"]
+noise = SubResource("FastNoiseLite_dt0d4")
+
+[sub_resource type="Gradient" id="Gradient_xdd4c"]
+colors = PackedColorArray(0.544975, 0.544974, 0.544974, 1, 1, 1, 1, 1)
+
+[sub_resource type="FastNoiseLite" id="FastNoiseLite_1axah"]
+
+[sub_resource type="NoiseTexture2D" id="NoiseTexture2D_ac3mp"]
+width = 256
+height = 2
+seamless = true
+color_ramp = SubResource("Gradient_xdd4c")
+noise = SubResource("FastNoiseLite_1axah")
+
+[sub_resource type="Gradient" id="Gradient_vcvu4"]
+offsets = PackedFloat32Array(0, 0.0447154, 0.170732, 0.390244, 0.943089)
+colors = PackedColorArray(0, 0, 0, 1, 1, 1, 1, 1, 0.69976, 0.69976, 0.69976, 1, 0.457013, 0.457013, 0.457013, 1, 0, 0, 0, 1)
+
+[sub_resource type="GradientTexture1D" id="GradientTexture1D_kua13"]
+gradient = SubResource("Gradient_vcvu4")
+
+[resource]
+render_priority = 0
+shader = ExtResource("1_fbhuf")
+shader_parameter/albedo = Color(0, 1, 0.301961, 1)
+shader_parameter/transpose_axis = false
+shader_parameter/wave_width = 1.0
+shader_parameter/wave_speed = 1.618
+shader_parameter/wave_gradient = SubResource("GradientTexture1D_kua13")
+shader_parameter/glow_color = Color(0.5, 0.75, 1, 1)
+shader_parameter/glow_intensity = 0.618
+shader_parameter/glow_amount = 4.5
+shader_parameter/pulse_speed = 4.0
+shader_parameter/pulse_gradient = SubResource("NoiseTexture2D_ac3mp")
+shader_parameter/edge_size = Vector2(0.1, 0.2)
+shader_parameter/edge_bias = Vector2(0, 0.5)
+shader_parameter/edge_speed = 0.3
+shader_parameter/edge_gradient = SubResource("NoiseTexture2D_hx2kx")
diff --git a/src/effects/laser_dust.tscn b/src/effects/laser_dust.tscn
new file mode 100644
index 0000000..e508f6e
--- /dev/null
+++ b/src/effects/laser_dust.tscn
@@ -0,0 +1,43 @@
+[gd_scene load_steps=6 format=3 uid="uid://oc6t5ubyybsa"]
+
+[sub_resource type="Curve" id="Curve_vlknk"]
+_data = [Vector2(0, 0.517742), 0.0, 0.0, 0, 0, Vector2(0.275194, 1), 0.0, 0.0, 0, 0, Vector2(1, 0), 0.0, 0.0, 0, 0]
+point_count = 3
+
+[sub_resource type="CurveTexture" id="CurveTexture_7ktnl"]
+curve = SubResource("Curve_vlknk")
+
+[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_etm00"]
+angle_min = -15.0
+angle_max = 15.0
+direction = Vector3(0, 0, 0)
+spread = 180.0
+initial_velocity_min = 2.0
+initial_velocity_max = 2.0
+gravity = Vector3(0, 0, 0)
+scale_curve = SubResource("CurveTexture_7ktnl")
+
+[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_fhbna"]
+transparency = 1
+vertex_color_use_as_albedo = true
+albedo_color = Color(0, 1, 0.301961, 0.392157)
+emission_enabled = true
+emission = Color(0, 1, 0.301961, 1)
+emission_energy_multiplier = 10.0
+texture_filter = 2
+billboard_mode = 3
+billboard_keep_scale = true
+particles_anim_h_frames = 1
+particles_anim_v_frames = 1
+particles_anim_loop = false
+
+[sub_resource type="QuadMesh" id="QuadMesh_s6kmk"]
+material = SubResource("StandardMaterial3D_fhbna")
+size = Vector2(0.02, 0.02)
+
+[node name="LaserDust" type="GPUParticles3D"]
+layers = 2
+amount = 32
+lifetime = 0.2
+process_material = SubResource("ParticleProcessMaterial_etm00")
+draw_pass_1 = SubResource("QuadMesh_s6kmk")
diff --git a/src/equipment/laser_cast/laser_cast.gd b/src/equipment/laser_cast/laser_cast.gd
new file mode 100644
index 0000000..4e96830
--- /dev/null
+++ b/src/equipment/laser_cast/laser_cast.gd
@@ -0,0 +1,23 @@
+class_name LaserCast extends RayCast3D
+## Raycast for particle beams
+
+const NORMAL_OFFSET = 0.05
+
+@export var parent_tool: Spray
+
+@onready var laser_dust: GPUParticles3D = %LaserDust
+@onready var glow_light: OmniLight3D = %GlowLight
+
+
+func _process(_delta: float) -> void:
+ if is_colliding() and parent_tool.firing:
+ var child_pos := get_collision_point() + get_collision_normal() * NORMAL_OFFSET
+
+ laser_dust.global_position = child_pos
+ laser_dust.emitting = true
+
+ glow_light.global_position = child_pos
+ glow_light.visible = true # TODO: tween maybe?
+ else:
+ laser_dust.emitting = false
+ glow_light.visible = false
diff --git a/src/equipment/laser_cast/laser_cast.tscn b/src/equipment/laser_cast/laser_cast.tscn
new file mode 100644
index 0000000..d407a27
--- /dev/null
+++ b/src/equipment/laser_cast/laser_cast.tscn
@@ -0,0 +1,19 @@
+[gd_scene load_steps=3 format=3 uid="uid://b8vradbaw61ga"]
+
+[ext_resource type="Script" path="res://src/equipment/laser_cast/laser_cast.gd" id="1_xntcr"]
+[ext_resource type="PackedScene" uid="uid://oc6t5ubyybsa" path="res://src/effects/laser_dust.tscn" id="2_m5xmf"]
+
+[node name="LaserCast" type="RayCast3D"]
+target_position = Vector3(0, 0, -2)
+script = ExtResource("1_xntcr")
+
+[node name="LaserDust" parent="." instance=ExtResource("2_m5xmf")]
+unique_name_in_owner = true
+
+[node name="GlowLight" type="OmniLight3D" parent="."]
+unique_name_in_owner = true
+layers = 2
+light_color = Color(0, 1, 0.301961, 1)
+light_energy = 0.3
+light_cull_mask = 4294967293
+shadow_enabled = true
diff --git a/src/equipment/point_spray/point_spray.gd b/src/equipment/point_spray/point_spray.gd
index 65bf547..02d14fa 100644
--- a/src/equipment/point_spray/point_spray.gd
+++ b/src/equipment/point_spray/point_spray.gd
@@ -3,22 +3,29 @@ class_name PointSpray extends Spray
@export var spray_scale := 3.0
-@onready var raycast: RayCast3D = %RayCast3D
+@onready var laser: LaserCast = %LaserCast
@onready var spray_effect: MeshInstance3D = %SprayEffect
+@onready var beam_particles_1: GPUParticles3D = $BeamParticles1
+@onready var beam_particles_2: GPUParticles3D = $BeamParticles2
-func fire() -> void:
- if raycast.is_colliding():
- var collider := raycast.get_collider()
+
+func _fire() -> void:
+ if laser.is_colliding():
+ var collider := laser.get_collider()
if collider is GunkBody:
- var point := raycast.get_collision_point()
- var point_scale := sqrt(point.distance_to(global_position)) * spray_scale
+ var point := laser.get_collision_point()
+ var point_scale := point.distance_to(global_position) * spray_scale
(collider as GunkBody).paint_continuous(
- point, raycast.get_collision_normal(), point_scale
+ point, laser.get_collision_normal(), point_scale
)
spray_effect.visible = true
+ beam_particles_1.emitting = true
+ beam_particles_2.emitting = true
-func idle() -> void:
+func _idle() -> void:
spray_effect.visible = false
+ beam_particles_1.emitting = false
+ beam_particles_2.emitting = false
diff --git a/src/equipment/point_spray/point_spray.tscn b/src/equipment/point_spray/point_spray.tscn
index 3e099b3..84f1fc8 100644
--- a/src/equipment/point_spray/point_spray.tscn
+++ b/src/equipment/point_spray/point_spray.tscn
@@ -1,35 +1,76 @@
-[gd_scene load_steps=5 format=3 uid="uid://cc102xko0u6yj"]
+[gd_scene load_steps=10 format=3 uid="uid://cc102xko0u6yj"]
[ext_resource type="Script" path="res://src/equipment/point_spray/point_spray.gd" id="1_2yl2v"]
+[ext_resource type="Material" uid="uid://c00gndxoepuqh" path="res://assets/materials/laser_spray.tres" id="2_0pfy3"]
[ext_resource type="Texture2D" uid="uid://bn0gcsy37ahto" path="res://assets/ui/hud/reticle_large.png" id="2_qcl8j"]
+[ext_resource type="PackedScene" uid="uid://b8vradbaw61ga" path="res://src/equipment/laser_cast/laser_cast.tscn" id="3_qmoff"]
-[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_ng43h"]
-transparency = 1
-shading_mode = 0
+[sub_resource type="CylinderMesh" id="CylinderMesh_j5thb"]
+material = ExtResource("2_0pfy3")
+top_radius = 0.0
+bottom_radius = 0.2
+height = 2.2
+radial_segments = 16
+
+[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_nc5qr"]
+direction = Vector3(0, 0, -1)
+spread = 4.0
+initial_velocity_min = 2.0
+initial_velocity_max = 2.0
+gravity = Vector3(0, 0, 0)
+
+[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_6k0bn"]
vertex_color_use_as_albedo = true
-albedo_color = Color(0, 1, 0.301961, 0.254902)
+albedo_color = Color(0, 1, 0.301961, 0.392157)
+emission_enabled = true
+emission = Color(0, 1, 0.301961, 1)
+emission_energy_multiplier = 10.0
+texture_filter = 2
+billboard_mode = 3
+billboard_keep_scale = true
+particles_anim_h_frames = 1
+particles_anim_v_frames = 1
+particles_anim_loop = false
-[sub_resource type="PrismMesh" id="PrismMesh_ow0jh"]
-material = SubResource("StandardMaterial3D_ng43h")
-size = Vector3(0.2, 2, 0.2)
+[sub_resource type="QuadMesh" id="QuadMesh_fgb4j"]
+material = SubResource("StandardMaterial3D_6k0bn")
+size = Vector2(0.01, 0.01)
+
+[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_vwgy4"]
+direction = Vector3(0, 0, -1)
+spread = 4.0
+initial_velocity_min = 1.0
+initial_velocity_max = 1.0
+gravity = Vector3(0, 0, 0)
[node name="PointSpray" type="Node3D"]
script = ExtResource("1_2yl2v")
-[node name="RayCast3D" type="RayCast3D" parent="."]
+[node name="LaserCast" parent="." node_paths=PackedStringArray("parent_tool") instance=ExtResource("3_qmoff")]
unique_name_in_owner = true
-target_position = Vector3(0, 0, -2)
+visible = false
+parent_tool = NodePath("..")
[node name="SprayEffect" type="MeshInstance3D" parent="."]
unique_name_in_owner = true
-transform = Transform3D(1, 0, 0, 0, -4.47035e-08, -1, 0, 1, -4.47035e-08, 0, 0, -1)
-visible = false
+transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 0, -1)
layers = 2
-mesh = SubResource("PrismMesh_ow0jh")
-skeleton = NodePath("../../../..")
+mesh = SubResource("CylinderMesh_j5thb")
+
+[node name="BeamParticles1" type="GPUParticles3D" parent="."]
+lifetime = 0.9
+process_material = SubResource("ParticleProcessMaterial_nc5qr")
+draw_pass_1 = SubResource("QuadMesh_fgb4j")
+
+[node name="BeamParticles2" type="GPUParticles3D" parent="."]
+amount = 16
+lifetime = 1.8
+process_material = SubResource("ParticleProcessMaterial_vwgy4")
+draw_pass_1 = SubResource("QuadMesh_fgb4j")
[node name="Decal" type="Decal" parent="."]
transform = Transform3D(1, 0, 0, 0, -4.47035e-08, -1, 0, 1, -4.47035e-08, 0, 0, -1)
size = Vector3(0.2, 2, 0.2)
texture_albedo = ExtResource("2_qcl8j")
+texture_emission = ExtResource("2_qcl8j")
cull_mask = 1048573
diff --git a/src/equipment/spray.gd b/src/equipment/spray.gd
index 4eca758..601248f 100644
--- a/src/equipment/spray.gd
+++ b/src/equipment/spray.gd
@@ -1,12 +1,24 @@
class_name Spray extends Node3D
## Abstract base class for spraygun types
+var firing := false
+
+
+func _fire() -> void:
+ pass
+
+
+func _idle() -> void:
+ pass
+
## Called each frame that this spray is being fired.
func fire() -> void:
- pass
+ firing = true
+ _fire()
## Called each frame that this spray is not being fired.
func idle() -> void:
- pass
+ firing = false
+ _idle()
diff --git a/src/equipment/spring_cast.gd b/src/equipment/spring_cast.gd
new file mode 100644
index 0000000..7ea154b
--- /dev/null
+++ b/src/equipment/spring_cast.gd
@@ -0,0 +1,13 @@
+class_name SpringCast extends RayCast3D
+## Raycast which places its children at the collision point (if any)
+
+@export var normal_offset := 0.0
+
+
+func _process(_delta: float) -> void:
+ if is_colliding():
+ for child: Node3D in get_children():
+ child.global_position = get_collision_point() + get_collision_normal() * normal_offset
+ visible = true
+ else:
+ visible = false
diff --git a/src/equipment/wide_spray/wide_spray.gd b/src/equipment/wide_spray/wide_spray.gd
index 758e9b1..f823dc1 100644
--- a/src/equipment/wide_spray/wide_spray.gd
+++ b/src/equipment/wide_spray/wide_spray.gd
@@ -6,20 +6,23 @@ const SPRAYCAST_GROUP := "SprayCast"
@export var spray_scale := 2.0
@onready var spray_casts: Node3D = %SprayCasts
-@onready var spray_effect: MeshInstance3D = %SprayEffect
+@onready var spray_effect: Node3D = %SprayEffect
+
+@onready var beam_particles_1: GPUParticles3D = $BeamParticles1
+@onready var beam_particles_2: GPUParticles3D = $BeamParticles2
-func fire() -> void:
+func _fire() -> void:
var prev_target: GunkBody = null
var prev_point: Vector3
var prev_normal: Vector3
- for raycast: RayCast3D in spray_casts.get_children():
- if raycast.is_colliding():
- var target := raycast.get_collider() as GunkBody
+ for laser: LaserCast in spray_casts.get_children():
+ if laser.is_colliding():
+ var target := laser.get_collider() as GunkBody
if target:
- var point := raycast.get_collision_point()
- var normal := raycast.get_collision_normal()
+ var point := laser.get_collision_point()
+ var normal := laser.get_collision_normal()
# Always paint at least a dot, to cap the ends of the line
target.paint_dot(point, normal, spray_scale)
@@ -33,7 +36,11 @@ func fire() -> void:
prev_normal = normal
spray_effect.visible = true
+ beam_particles_1.emitting = true
+ beam_particles_2.emitting = true
-func idle() -> void:
+func _idle() -> void:
spray_effect.visible = false
+ beam_particles_1.emitting = false
+ beam_particles_2.emitting = false
diff --git a/src/equipment/wide_spray/wide_spray.tscn b/src/equipment/wide_spray/wide_spray.tscn
index ce3f73f..9b5aef7 100644
--- a/src/equipment/wide_spray/wide_spray.tscn
+++ b/src/equipment/wide_spray/wide_spray.tscn
@@ -1,23 +1,50 @@
-[gd_scene load_steps=9 format=3 uid="uid://d2hnxr5l6w2x4"]
+[gd_scene load_steps=12 format=3 uid="uid://d2hnxr5l6w2x4"]
[ext_resource type="Script" path="res://src/equipment/wide_spray/wide_spray.gd" id="1_ggkto"]
-[ext_resource type="Texture2D" uid="uid://dwavqltjrmupx" path="res://assets/ui/hud/wide_reticle_large.png" id="2_d01sr"]
+[ext_resource type="Material" uid="uid://c00gndxoepuqh" path="res://assets/materials/laser_spray.tres" id="2_26efp"]
[ext_resource type="Texture2D" uid="uid://cx28sj02y31kj" path="res://assets/ui/hud/reticle_crosshair.png" id="3_78jy6"]
+[ext_resource type="PackedScene" uid="uid://b8vradbaw61ga" path="res://src/equipment/laser_cast/laser_cast.tscn" id="3_xahet"]
[ext_resource type="Texture2D" uid="uid://carrggw6kp14w" path="res://assets/ui/hud/reticle_left.png" id="4_rotxf"]
[ext_resource type="Texture2D" uid="uid://wp03nuwt8hp5" path="res://assets/ui/hud/reticle_right.png" id="5_xo3vu"]
-[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_cdyoo"]
-transparency = 1
-shading_mode = 0
+[sub_resource type="CylinderMesh" id="CylinderMesh_48buk"]
+material = ExtResource("2_26efp")
+top_radius = 0.0
+bottom_radius = 0.7
+radial_segments = 6
+
+[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_pr4yq"]
+direction = Vector3(0, 0, -1)
+spread = 15.0
+flatness = 0.82
+initial_velocity_min = 2.0
+initial_velocity_max = 2.0
+gravity = Vector3(0, 0, 0)
+
+[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_6k0bn"]
vertex_color_use_as_albedo = true
-albedo_color = Color(0, 1, 0.301961, 0.254902)
+albedo_color = Color(0, 1, 0.301961, 0.392157)
+emission_enabled = true
+emission = Color(0, 1, 0.301961, 1)
+emission_energy_multiplier = 10.0
+texture_filter = 2
+billboard_mode = 3
+billboard_keep_scale = true
+particles_anim_h_frames = 1
+particles_anim_v_frames = 1
+particles_anim_loop = false
-[sub_resource type="PrismMesh" id="PrismMesh_vh2mt"]
-material = SubResource("StandardMaterial3D_cdyoo")
-size = Vector3(1, 2, 0.2)
+[sub_resource type="QuadMesh" id="QuadMesh_trcry"]
+material = SubResource("StandardMaterial3D_6k0bn")
+size = Vector2(0.01, 0.01)
-[sub_resource type="QuadMesh" id="QuadMesh_lvw1u"]
-size = Vector2(2, 2)
+[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_lyk2j"]
+direction = Vector3(0, 0, -1)
+spread = 15.0
+flatness = 0.82
+initial_velocity_min = 1.0
+initial_velocity_max = 1.0
+gravity = Vector3(0, 0, 0)
[node name="WideSpray" type="Node3D"]
script = ExtResource("1_ggkto")
@@ -25,41 +52,38 @@ script = ExtResource("1_ggkto")
[node name="SprayCasts" type="Node3D" parent="."]
unique_name_in_owner = true
-[node name="RayCast3D" type="RayCast3D" parent="SprayCasts"]
+[node name="LaserCast" parent="SprayCasts" node_paths=PackedStringArray("parent_tool") instance=ExtResource("3_xahet")]
target_position = Vector3(-0.5, 0, -2)
+parent_tool = NodePath("../..")
-[node name="RayCast3D2" type="RayCast3D" parent="SprayCasts"]
+[node name="LaserCast2" parent="SprayCasts" node_paths=PackedStringArray("parent_tool") instance=ExtResource("3_xahet")]
target_position = Vector3(-0.333, 0, -2)
+parent_tool = NodePath("../..")
-[node name="RayCast3D3" type="RayCast3D" parent="SprayCasts"]
+[node name="LaserCast3" parent="SprayCasts" node_paths=PackedStringArray("parent_tool") instance=ExtResource("3_xahet")]
target_position = Vector3(-0.167, 0, -2)
+parent_tool = NodePath("../..")
-[node name="RayCast3D4" type="RayCast3D" parent="SprayCasts"]
-target_position = Vector3(0, 0, -2)
+[node name="LaserCast4" parent="SprayCasts" node_paths=PackedStringArray("parent_tool") instance=ExtResource("3_xahet")]
+parent_tool = NodePath("../..")
-[node name="RayCast3D5" type="RayCast3D" parent="SprayCasts"]
+[node name="LaserCast5" parent="SprayCasts" node_paths=PackedStringArray("parent_tool") instance=ExtResource("3_xahet")]
target_position = Vector3(0.167, 0, -2)
+parent_tool = NodePath("../..")
-[node name="RayCast3D6" type="RayCast3D" parent="SprayCasts"]
+[node name="LaserCast6" parent="SprayCasts" node_paths=PackedStringArray("parent_tool") instance=ExtResource("3_xahet")]
target_position = Vector3(0.333, 0, -2)
+parent_tool = NodePath("../..")
-[node name="RayCast3D7" type="RayCast3D" parent="SprayCasts"]
+[node name="LaserCast7" parent="SprayCasts" node_paths=PackedStringArray("parent_tool") instance=ExtResource("3_xahet")]
target_position = Vector3(0.5, 0, -2)
+parent_tool = NodePath("../..")
[node name="SprayEffect" type="MeshInstance3D" parent="."]
unique_name_in_owner = true
-transform = Transform3D(1, 0, 0, 0, -4.47035e-08, -1, 0, 1, -4.47035e-08, 0, 0, -1)
-visible = false
+transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -0.15, 0, 1, -6.55671e-09, 0, 0, -1)
layers = 2
-mesh = SubResource("PrismMesh_vh2mt")
-skeleton = NodePath("../../../..")
-
-[node name="Decal" type="Decal" parent="."]
-transform = Transform3D(1, 0, 0, 0, -4.47035e-08, -1, 0, 1, -4.47035e-08, 0, 0, -1)
-visible = false
-size = Vector3(1, 10, 0.2)
-texture_albedo = ExtResource("2_d01sr")
-cull_mask = 1048573
+mesh = SubResource("CylinderMesh_48buk")
[node name="ReticleDecals" type="Node3D" parent="."]
@@ -87,7 +111,13 @@ size = Vector3(0.2, 2, 0.2)
texture_albedo = ExtResource("5_xo3vu")
cull_mask = 1048573
-[node name="DebugMesh" type="MeshInstance3D" parent="."]
-transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -1.67743)
-visible = false
-mesh = SubResource("QuadMesh_lvw1u")
+[node name="BeamParticles1" type="GPUParticles3D" parent="."]
+lifetime = 0.9
+process_material = SubResource("ParticleProcessMaterial_pr4yq")
+draw_pass_1 = SubResource("QuadMesh_trcry")
+
+[node name="BeamParticles2" type="GPUParticles3D" parent="."]
+amount = 16
+lifetime = 1.8
+process_material = SubResource("ParticleProcessMaterial_lyk2j")
+draw_pass_1 = SubResource("QuadMesh_trcry")
diff --git a/src/player/camera_controller.gd b/src/player/camera_controller.gd
index 948e146..7a438e9 100644
--- a/src/player/camera_controller.gd
+++ b/src/player/camera_controller.gd
@@ -2,7 +2,7 @@ class_name CameraController extends Node3D
const PITCH_LIMIT := deg_to_rad(85.0)
const FOCUS_SENSITIVITY := 0.2
-const FOCUS_ACCELERATION := 3
+const FOCUS_ACCELERATION := 8
@onready var player: Player = owner
diff --git a/src/player/player.tscn b/src/player/player.tscn
index 842c117..2558c0f 100644
--- a/src/player/player.tscn
+++ b/src/player/player.tscn
@@ -28,9 +28,11 @@ transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.15, -0.1, -0.1)
unique_name_in_owner = true
transform = Transform3D(1, 0, 0, 0, 0.997564, -0.0697565, 0, 0.0697565, 0.997564, 0, 0, -0.15)
-[node name="WideSpray" parent="CameraPivot/SprayMount/SprayMuzzle" instance=ExtResource("3_ibq07")]
-
[node name="PointSpray" parent="CameraPivot/SprayMount/SprayMuzzle" instance=ExtResource("3_6wgkm")]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)
+
+[node name="WideSpray" parent="CameraPivot/SprayMount/SprayMuzzle" instance=ExtResource("3_ibq07")]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)
visible = false
[node name="SprayRumbler" type="Node3D" parent="CameraPivot/SprayMount"]
diff --git a/src/shaders/gunk.gdshader b/src/shaders/gunk.gdshader
index 2379d40..980aa3f 100644
--- a/src/shaders/gunk.gdshader
+++ b/src/shaders/gunk.gdshader
@@ -1,5 +1,5 @@
shader_type spatial;
-render_mode blend_mix, depth_draw_opaque, cull_back, diffuse_burley, specular_schlick_ggx, sss_mode_skin;
+render_mode blend_mix, depth_draw_opaque, cull_disabled, diffuse_burley, specular_schlick_ggx, sss_mode_skin;
uniform vec3 color_1: source_color = vec3(0.0, 0.03, 0.1);
uniform vec3 color_2: source_color = vec3(0.0, 0.1, 0.3);
diff --git a/src/shaders/hologram.gdshader b/src/shaders/hologram.gdshader
new file mode 100644
index 0000000..e66a446
--- /dev/null
+++ b/src/shaders/hologram.gdshader
@@ -0,0 +1,47 @@
+// Hologram shader
+// Adapted from https://godotshaders.com/shader/scifi-hologram/
+
+shader_type spatial;
+render_mode unshaded;
+
+uniform sampler2D texture_image;
+
+uniform mediump vec4 line_color : source_color = vec4(0.0, 1.0, 0.0, 1.0);
+uniform mediump float line_width : hint_range(0, 1) = 0.005;
+uniform mediump float line_blur : hint_range(0, 1) = 0.2;
+uniform mediump float line_speed : hint_range(-1, 1) = 0.02;
+uniform bool straight_lines = true;
+
+uniform mediump float interrupt_width : hint_range(0, 1) = 0.5;
+uniform mediump float interrupt_blur : hint_range(0, 1) = 0.25;
+uniform mediump float interrupt_speed : hint_range(-1, 1) = 0.2;
+
+uniform mediump vec4 glow_color : source_color = vec4(0.5, 0.75, 1.0, 1.0);
+uniform lowp float glow_itensity : hint_range(0, 20) = 4.5;
+uniform lowp float glow_amount : hint_range(0, 20) = 4.5;
+uniform lowp float flickering : hint_range(0, 1) = 0.55;
+
+vec3 fresnel_glow(float amount, float intensity, vec3 color, vec3 normal, vec3 view) {
+ return pow((1.0 - dot(normalize(normal), normalize(view))), amount) * color * intensity;
+}
+
+void fragment () {
+ vec2 canvas;
+ if (straight_lines) {
+ canvas = SCREEN_UV;
+ } else {
+ canvas = vec2(VIEW.x, VIEW.y);
+ }
+ vec2 lines = vec2(clamp(sin((TIME * line_speed + canvas.y) / line_width), line_blur, 1.0 - line_blur), canvas.x);
+ vec2 interupts = vec2(clamp(sin((TIME * interrupt_speed + canvas.y) / interrupt_width * 3.0), interrupt_blur, 1.0 - interrupt_blur), canvas.x);
+
+ float flicker = clamp(fract(cos(TIME) * 43758.5453123), flickering, 1.0);
+ vec4 imgtex = flicker * line_color * texture(texture_image, lines * interupts);
+ vec3 imgtex_color = vec3(imgtex.r, imgtex.g, imgtex.b);
+ vec3 fresnel_color = vec3(glow_color.r, glow_color.g, glow_color.b);
+ vec3 fresnel = fresnel_glow(glow_amount, glow_itensity, fresnel_color, NORMAL, VIEW);
+ ALBEDO = imgtex_color + fresnel;
+
+ EMISSION = glow_amount * vec3(glow_color.r, glow_color.g, glow_color.b);
+ ALPHA = lines.x * interupts.x;
+}
\ No newline at end of file
diff --git a/src/shaders/plasma.gdshader b/src/shaders/plasma.gdshader
new file mode 100644
index 0000000..5a974cc
--- /dev/null
+++ b/src/shaders/plasma.gdshader
@@ -0,0 +1,59 @@
+// Plasma Pulse shader
+// Adapted from https://godotshaders.com/shader/scifi-hologram/
+
+shader_type spatial;
+render_mode unshaded, cull_back;
+
+uniform mediump vec3 albedo: source_color = vec3(0.9, 0.0, 0.7);
+
+uniform bool transpose_axis = false;
+
+group_uniforms wave;
+uniform mediump sampler2D wave_gradient;
+uniform mediump float wave_width: hint_range(0, 10) = 1;
+uniform mediump float wave_speed = 0.4;
+
+group_uniforms glow;
+uniform mediump vec4 glow_color: source_color = vec4(0.5, 0.75, 1.0, 1.0);
+uniform lowp float glow_intensity: hint_range(0, 20) = 0.618;
+uniform lowp float glow_amount: hint_range(0, 20) = 4.5;
+
+group_uniforms pulse;
+uniform mediump sampler2D pulse_gradient;
+uniform mediump float pulse_speed: hint_range(0, 10) = 0.3;
+
+group_uniforms edge_wave;
+uniform mediump sampler2D edge_gradient;
+uniform mediump vec2 edge_size = vec2(0.1, 0.05);
+uniform mediump vec2 edge_bias = vec2(0.0, 0.5);
+uniform mediump float edge_speed = 0.3;
+
+vec3 fresnel_glow(float amount, float intensity, vec3 color, vec3 normal, vec3 view) {
+ return pow((1.0 - dot(normalize(normal), normalize(view))), amount) * color * intensity;
+}
+
+void fragment () {
+ float canvas = -UV.x;
+ float t_canvas = UV.y;
+ if(transpose_axis) {
+ canvas = -UV.y;
+ t_canvas = UV.x;
+ }
+ float wave_value = texture(wave_gradient, vec2((canvas + TIME * wave_speed) / wave_width, 0)).r;
+
+ vec3 fresnel_color = vec3(glow_color.r, glow_color.g, glow_color.b);
+ vec3 fresnel = fresnel_glow(glow_amount, glow_intensity, fresnel_color, NORMAL, VIEW);
+
+ float pulse_value = texture(pulse_gradient, vec2(TIME * pulse_speed, 0)).r;
+
+ float edge_sample = texture(edge_gradient, vec2(canvas, TIME * edge_speed)).r;
+ vec2 edge = edge_sample * edge_size + edge_bias;
+ float edge_factor = 1.0;
+ if(t_canvas < edge.x || t_canvas > 1.0 - edge.y) {
+ edge_factor = 0.0;
+ }
+
+ ALBEDO = albedo + fresnel;
+ EMISSION = glow_amount * vec3(glow_color.r, glow_color.g, glow_color.b);
+ ALPHA = wave_value * pulse_value * edge_factor;
+}
\ No newline at end of file
diff --git a/src/world/gunk_body/gunk_body.tscn b/src/world/gunk_body/gunk_body.tscn
index 4c0be0f..ea07f44 100644
--- a/src/world/gunk_body/gunk_body.tscn
+++ b/src/world/gunk_body/gunk_body.tscn
@@ -25,6 +25,7 @@ grow_vertical = 2
script = ExtResource("2_kkcjw")
[node name="DebugDraw" type="Control" parent="."]
+visible = false
layout_mode = 3
anchors_preset = 0
offset_right = 40.0
diff --git a/vault/assets/color_palette.md b/vault/assets/color_palette.md
index 6529ea7..06666a6 100644
--- a/vault/assets/color_palette.md
+++ b/vault/assets/color_palette.md
@@ -1,3 +1,6 @@
+## Player
+- \#00ff4d Laser Green SAMPLE
+
## Grunk
- \#001a4d Grunk Blue SAMPLE
- \#00081a Grunk Dark Blue SAMPLE