pellet spread, bulletholes and balance fixes

This commit is contained in:
Rendo 2025-12-14 14:54:35 +05:00
commit 74e37f8a18
17 changed files with 261 additions and 72 deletions

View file

@ -2,7 +2,7 @@ extends Node
func can_buy(player_id: int,weapon: WeaponResource) -> bool: func can_buy(player_id: int,weapon: WeaponResource) -> bool:
return Session.player_data[player_id]["money"] >= weapon.cost return Session.player_data[player_id]["money"] >= weapon.cost or LobbySettings.infinite_money
func buy(player_id: int, weapon: WeaponResource) -> void: func buy(player_id: int, weapon: WeaponResource) -> void:
if not multiplayer.is_server() or can_buy(player_id,weapon) == false: if not multiplayer.is_server() or can_buy(player_id,weapon) == false:
@ -27,6 +27,7 @@ func buy(player_id: int, weapon: WeaponResource) -> void:
var player_data = Session.player_data[player_id] var player_data = Session.player_data[player_id]
player_data["money"] -= weapon.cost if not LobbySettings.infinite_money:
player_data["money"] -= weapon.cost
weapon_system.add(weapon.weapon_system_scene.instantiate(),slot) weapon_system.add(weapon.weapon_system_scene.instantiate(),slot)

View file

@ -10,6 +10,7 @@ func _ready() -> void:
%RoundBox.set_value_no_signal(LobbySettings.win_score) %RoundBox.set_value_no_signal(LobbySettings.win_score)
%AllowMultipleAbilityButton.set_pressed_no_signal(LobbySettings.allow_multiple_abilities) %AllowMultipleAbilityButton.set_pressed_no_signal(LobbySettings.allow_multiple_abilities)
%AllowTeamSwitch.set_pressed_no_signal(LobbySettings.allow_team_switch) %AllowTeamSwitch.set_pressed_no_signal(LobbySettings.allow_team_switch)
%InfiniteMoney.set_pressed_no_signal(LobbySettings.infinite_money)
var popup: PopupMenu = %MapsButton.get_popup() var popup: PopupMenu = %MapsButton.get_popup()
%MapsButton.text = LobbySettings.selected_map %MapsButton.text = LobbySettings.selected_map
@ -53,3 +54,7 @@ func _on_allow_team_switch_toggled(toggled_on: bool) -> void:
func on_maps_index_pressed(index: int): func on_maps_index_pressed(index: int):
%MapsButton.text = levels_by_index[index] %MapsButton.text = levels_by_index[index]
LobbySettings.selected_map = levels_by_index[index] LobbySettings.selected_map = levels_by_index[index]
func _on_infinite_money_toggled(toggled_on: bool) -> void:
LobbySettings.infinite_money = toggled_on

View file

@ -112,14 +112,24 @@ layout_mode = 2
folded = true folded = true
title = "Геймплей" title = "Геймплей"
[node name="AllowMultipleAbilityButton" type="CheckButton" parent="Gameplay"] [node name="VBoxContainer" type="VBoxContainer" parent="Gameplay"]
unique_name_in_owner = true
visible = false visible = false
layout_mode = 2
[node name="AllowMultipleAbilityButton" type="CheckButton" parent="Gameplay/VBoxContainer"]
unique_name_in_owner = true
custom_minimum_size = Vector2(200, 0) custom_minimum_size = Vector2(200, 0)
layout_mode = 2 layout_mode = 2
text = "Неограниченная закупка абилок" text = "Неограниченная закупка абилок"
autowrap_mode = 2 autowrap_mode = 2
[node name="InfiniteMoney" type="CheckButton" parent="Gameplay/VBoxContainer"]
unique_name_in_owner = true
custom_minimum_size = Vector2(200, 0)
layout_mode = 2
text = "Бесконечные деньги"
autowrap_mode = 2
[node name="PortForward" type="FoldableContainer" parent="."] [node name="PortForward" type="FoldableContainer" parent="."]
layout_mode = 2 layout_mode = 2
folded = true folded = true
@ -166,7 +176,8 @@ text = "Перемешать"
[connection signal="value_changed" from="Time/VBoxContainer/BuyTime/BuyTimeBox" to="." method="_on_buy_time_box_value_changed"] [connection signal="value_changed" from="Time/VBoxContainer/BuyTime/BuyTimeBox" to="." method="_on_buy_time_box_value_changed"]
[connection signal="value_changed" from="Round/VBoxContainer/RoundAmount/RoundBox" to="." method="_on_round_box_value_changed"] [connection signal="value_changed" from="Round/VBoxContainer/RoundAmount/RoundBox" to="." method="_on_round_box_value_changed"]
[connection signal="value_changed" from="Round/VBoxContainer/TeamSwitchAmount/TeamSwitchBox" to="." method="_on_team_switch_box_value_changed"] [connection signal="value_changed" from="Round/VBoxContainer/TeamSwitchAmount/TeamSwitchBox" to="." method="_on_team_switch_box_value_changed"]
[connection signal="toggled" from="Gameplay/AllowMultipleAbilityButton" to="." method="_on_allow_multiple_ability_button_toggled"] [connection signal="toggled" from="Gameplay/VBoxContainer/AllowMultipleAbilityButton" to="." method="_on_allow_multiple_ability_button_toggled"]
[connection signal="toggled" from="Gameplay/VBoxContainer/InfiniteMoney" to="." method="_on_infinite_money_toggled"]
[connection signal="update_ip" from="PortForward/PortForwardContainer/ForwardPortButton" to="PortForward/PortForwardContainer/PublicIP" method="on_update_ip"] [connection signal="update_ip" from="PortForward/PortForwardContainer/ForwardPortButton" to="PortForward/PortForwardContainer/PublicIP" method="on_update_ip"]
[connection signal="toggled" from="Teams/VBoxContainer/AllowTeamSwitch" to="." method="_on_allow_team_switch_toggled"] [connection signal="toggled" from="Teams/VBoxContainer/AllowTeamSwitch" to="." method="_on_allow_team_switch_toggled"]
[connection signal="pressed" from="Teams/VBoxContainer/Shuffle" to="." method="_on_shuffle_pressed"] [connection signal="pressed" from="Teams/VBoxContainer/Shuffle" to="." method="_on_shuffle_pressed"]

View file

@ -298,7 +298,7 @@ script = ExtResource("11_02ic3")
exlusion_list = [NodePath("MultiplayerSpawner"), NodePath("Bomb"), NodePath("Parenter")] exlusion_list = [NodePath("MultiplayerSpawner"), NodePath("Bomb"), NodePath("Parenter")]
[node name="MultiplayerSpawner" type="MultiplayerSpawner" parent="DynamicObjectsContainer"] [node name="MultiplayerSpawner" type="MultiplayerSpawner" parent="DynamicObjectsContainer"]
_spawnable_scenes = PackedStringArray("uid://cxdgk74ln5xpn", "uid://dtbpyfdawb02b", "uid://dgfqppi21c2u0", "uid://b6qahd6q60js7", "uid://l4t1mflutm3t", "uid://b3xux7url8d2s") _spawnable_scenes = PackedStringArray("uid://cxdgk74ln5xpn", "uid://dtbpyfdawb02b", "uid://dgfqppi21c2u0", "uid://b6qahd6q60js7", "uid://l4t1mflutm3t", "uid://b3xux7url8d2s", "uid://u8aj6fs32ql6")
spawn_path = NodePath("..") spawn_path = NodePath("..")
[node name="Parenter" type="Node" parent="DynamicObjectsContainer"] [node name="Parenter" type="Node" parent="DynamicObjectsContainer"]

View file

@ -9,4 +9,5 @@ var buy_time: float = 15.0
var round_time: float = 150.0 var round_time: float = 150.0
var allow_multiple_abilities: bool = false var allow_multiple_abilities: bool = false
var allow_team_switch: bool = true var allow_team_switch: bool = true
var infinite_money: bool = false
var selected_map: StringName = "prototype" var selected_map: StringName = "prototype"

View file

@ -1,5 +1,7 @@
extends Node extends Node
const BULLET_HOLE: PackedScene = preload("uid://u8aj6fs32ql6")
enum TEAMS { enum TEAMS {
DEFENCE, DEFENCE,
ATTACK, ATTACK,
@ -325,56 +327,8 @@ func shoot(id:int , limb_damage: int, torso_damage: int,head_damage: int, distan
var collision = space.intersect_ray(ray) var collision = space.intersect_ray(ray)
if collision != {} and collision["collider"] is Player: if collision != {}:
var hit_player: Player = collision["collider"] if collision["collider"] is Player:
var shape_object: CollisionShape3D = hit_player.shape_owner_get_owner(collision["shape"])
var reduction: float = 1
var damage: int = 0
match shape_object.get_groups()[0]:
"Head":
damage = head_damage
"Limb":
damage = limb_damage
_:
damage = torso_damage
if damage_reduction_curve != null:
var distance_to_hit = (player_camera.global_position - collision["position"]).length()/distance
reduction = damage_reduction_curve.sample(distance_to_hit)
hit_player.take_damage(int(float(damage) * reduction))
func shoot_pellets(id:int,amount: int, limb_total_damage: int, torso_total_damage: int,head_total_damage: int, distance: float, arc: float, damage_reduction_curve: Curve = null):
if multiplayer.is_server() == false:
return
var player: Player = player_nodes[id]
var player_camera: Camera3D = player.get_node("Camera3D")
var space: PhysicsDirectSpaceState3D = player.get_world_3d().direct_space_state
var head_damage: int = head_total_damage / amount
var torso_damage: int = torso_total_damage / amount
var limb_damage: int = limb_total_damage / amount
for i in range(amount):
var endpoint: Vector3 = player_camera.global_position - player_camera.global_basis.z.rotated(Vector3.RIGHT,randf_range(-arc/2,arc/2)).rotated(Vector3.UP,randf_range(-arc/2,arc/2)) * distance
var ray = PhysicsRayQueryParameters3D.create(player_camera.global_position,endpoint,1)
ray.exclude = [player.get_rid()]
ray.collide_with_areas = false
match player.team:
TEAMS.DEFENCE:
ray.collision_mask |= ATTACK_LAYER
TEAMS.ATTACK:
ray.collision_mask |= DEFENCE_LAYER
_:
ray.collision_mask |= ATTACK_LAYER | DEFENCE_LAYER
var collision = space.intersect_ray(ray)
if collision != {} and collision["collider"] is Player:
var hit_player: Player = collision["collider"] var hit_player: Player = collision["collider"]
var shape_object: CollisionShape3D = hit_player.shape_owner_get_owner(collision["shape"]) var shape_object: CollisionShape3D = hit_player.shape_owner_get_owner(collision["shape"])
var reduction: float = 1 var reduction: float = 1
@ -393,6 +347,71 @@ func shoot_pellets(id:int,amount: int, limb_total_damage: int, torso_total_damag
reduction = damage_reduction_curve.sample(distance_to_hit) reduction = damage_reduction_curve.sample(distance_to_hit)
hit_player.take_damage(int(float(damage) * reduction)) hit_player.take_damage(int(float(damage) * reduction))
var bullet_hole: Decal = BULLET_HOLE.instantiate()
dynamic_objects_parent.add_child(bullet_hole,true)
var rotation_quat: Quaternion = Quaternion(Vector3.UP,collision["normal"])
bullet_hole.quaternion *= rotation_quat
bullet_hole.global_position = collision["position"]
func shoot_pellets(id:int,limb_pellet_damage: int, torso_pellet_damage: int,head_pellet_damage: int, distance: float, pellets: PackedVector2Array, damage_reduction_curve: Curve = null):
if multiplayer.is_server() == false:
return
var amount: int = len(pellets)
var player: Player = player_nodes[id]
var player_camera: Camera3D = player.get_node("Camera3D")
var space: PhysicsDirectSpaceState3D = player.get_world_3d().direct_space_state
for i in range(amount):
var endpoint: Vector3 = player_camera.project_position(pellets[i],distance)
var ray = PhysicsRayQueryParameters3D.create(player_camera.global_position,endpoint,1)
ray.exclude = [player.get_rid()]
ray.collide_with_areas = false
match player.team:
TEAMS.DEFENCE:
ray.collision_mask |= ATTACK_LAYER
TEAMS.ATTACK:
ray.collision_mask |= DEFENCE_LAYER
_:
ray.collision_mask |= ATTACK_LAYER | DEFENCE_LAYER
var collision = space.intersect_ray(ray)
if collision != {}:
if collision["collider"] is Player:
var hit_player: Player = collision["collider"]
var shape_object: CollisionShape3D = hit_player.shape_owner_get_owner(collision["shape"])
var reduction: float = 1
var damage: int = 0
match shape_object.get_groups()[0]:
"Head":
damage = head_pellet_damage
"Limb":
damage = limb_pellet_damage
_:
damage = torso_pellet_damage
if damage_reduction_curve != null:
var distance_to_hit = (player_camera.global_position - collision["position"]).length()/distance
reduction = damage_reduction_curve.sample(distance_to_hit)
hit_player.take_damage(int(float(damage) * reduction))
var bullet_hole: Decal = BULLET_HOLE.instantiate()
dynamic_objects_parent.add_child(bullet_hole,true)
var rotation_quat: Quaternion = Quaternion(Vector3.UP,collision["normal"])
bullet_hole.quaternion *= rotation_quat
bullet_hole.global_position = collision["position"]
func interact(id: int) -> void: func interact(id: int) -> void:
if multiplayer.is_server() == false: if multiplayer.is_server() == false:

BIN
textures/bullet_hole.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View file

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://djb2h4sf42nqq"
path="res://.godot/imported/bullet_hole.png-c5594de24f88f66a649756099fb11bb7.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://textures/bullet_hole.png"
dest_files=["res://.godot/imported/bullet_hole.png-c5594de24f88f66a649756099fb11bb7.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

View file

@ -0,0 +1,27 @@
[gd_scene load_steps=3 format=3 uid="uid://u8aj6fs32ql6"]
[ext_resource type="Texture2D" uid="uid://djb2h4sf42nqq" path="res://textures/bullet_hole.png" id="1_wpexx"]
[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_wpexx"]
properties/0/path = NodePath(".:position")
properties/0/spawn = true
properties/0/replication_mode = 1
properties/1/path = NodePath(".:rotation")
properties/1/spawn = true
properties/1/replication_mode = 1
[node name="BulletHole" type="Decal"]
size = Vector3(0.25, 0.5, 0.25)
texture_albedo = ExtResource("1_wpexx")
[node name="Timer" type="Timer" parent="."]
process_mode = 3
wait_time = 60.0
one_shot = true
autostart = true
ignore_time_scale = true
[node name="MultiplayerSynchronizer" type="MultiplayerSynchronizer" parent="."]
replication_config = SubResource("SceneReplicationConfig_wpexx")
[connection signal="timeout" from="Timer" to="." method="queue_free"]

View file

@ -1,10 +1,11 @@
[gd_scene load_steps=10 format=3 uid="uid://8ohlfmr5bp0k"] [gd_scene load_steps=12 format=3 uid="uid://8ohlfmr5bp0k"]
[ext_resource type="Script" uid="uid://e6lqknfl4ngt" path="res://systems/weapon_system/weapon_substate_machine.gd" id="1_uck67"] [ext_resource type="Script" uid="uid://e6lqknfl4ngt" path="res://systems/weapon_system/weapon_substate_machine.gd" id="1_uck67"]
[ext_resource type="Script" uid="uid://ofv4e3dsfe8" path="res://weapons/gun/idle_state.gd" id="2_rkf02"] [ext_resource type="Script" uid="uid://ofv4e3dsfe8" path="res://weapons/gun/idle_state.gd" id="2_rkf02"]
[ext_resource type="Script" uid="uid://cvueeftqbxb7r" path="res://weapons/gun/semi_pellet_shoot_state.gd" id="3_jk5g7"] [ext_resource type="Script" uid="uid://cvueeftqbxb7r" path="res://weapons/gun/semi_pellet_shoot_state.gd" id="3_jk5g7"]
[ext_resource type="Script" uid="uid://hmekwp8444ao" path="res://weapons/gun/reload_state.gd" id="4_fs8hh"] [ext_resource type="Script" uid="uid://hmekwp8444ao" path="res://weapons/gun/reload_state.gd" id="4_fs8hh"]
[ext_resource type="Script" uid="uid://bmj0bwy2tlian" path="res://weapons/gun/intro_state.gd" id="5_3ok4b"] [ext_resource type="Script" uid="uid://bmj0bwy2tlian" path="res://weapons/gun/intro_state.gd" id="5_3ok4b"]
[ext_resource type="Script" uid="uid://ryxe3lxtvpk4" path="res://weapons/gun/pellet_spread/pellet_spread.gd" id="6_a53f6"]
[sub_resource type="Curve" id="Curve_cmn6f"] [sub_resource type="Curve" id="Curve_cmn6f"]
_limits = [0.0, 0.1, 0.0, 20.0] _limits = [0.0, 0.1, 0.0, 20.0]
@ -27,6 +28,12 @@ properties/1/path = NodePath(".:remaining_ammo")
properties/1/spawn = true properties/1/spawn = true
properties/1/replication_mode = 2 properties/1/replication_mode = 2
[sub_resource type="Curve2D" id="Curve2D_0fc4q"]
_data = {
"points": PackedVector2Array(0, 0, 0, 0, 0, -10, 0, 0, 0, 0, 9, -7, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, -8, -3, 0, 0, 0, 0, -8, 5, 0, 0, 0, 0, -1, 7, 0, 0, 0, 0, 7, 6, 0, 0, 0, 0, 14, 6, 0, 0, 0, 0, 15, -5, 0, 0, 0, 0, 0, -7, 0, 0, 0, 0, -13, -7, 0, 0, 0, 0, -10, 4, 0, 0, 0, 0, -10, 12, 0, 0, 0, 0, -1, 13, 0, 0, 0, 0, 12, 14, 0, 0, 0, 0, 6, 11, 0, 0, 0, 0, 21, 9, 0, 0, 0, 0, 21, 0, 0, 0, 0, 0, 9, -16, 0, 0, 0, 0, -10, -13, 0, 0, 0, 0, -16, -2, 0, 0, 0, 0, -17, 13, 0, 0, 0, 0, -3, 19, 0, 0, 0, 0, 6, 16, 0, 0, 0, 0, 18, 16, 0, 0, 0, 0, 24, 9, 0, 0, 0, 0, 23, -7, 0, 0, 0, 0, 20, -12)
}
point_count = 28
[node name="MC255" type="Node" node_paths=PackedStringArray("enter_state")] [node name="MC255" type="Node" node_paths=PackedStringArray("enter_state")]
script = ExtResource("1_uck67") script = ExtResource("1_uck67")
animation_prefix = &"baked_mc_" animation_prefix = &"baked_mc_"
@ -41,17 +48,15 @@ metadata/_custom_type_script = "uid://e6lqknfl4ngt"
[node name="Idle" type="Node" parent="."] [node name="Idle" type="Node" parent="."]
script = ExtResource("2_rkf02") script = ExtResource("2_rkf02")
[node name="Shoot" type="Node" parent="." node_paths=PackedStringArray("fire_timer")] [node name="Shoot" type="Node" parent="." node_paths=PackedStringArray("pellet_spread", "fire_timer")]
script = ExtResource("3_jk5g7") script = ExtResource("3_jk5g7")
vertical_curve = SubResource("Curve_cmn6f") vertical_curve = SubResource("Curve_cmn6f")
horizontal_curve = SubResource("Curve_jk5g7") horizontal_curve = SubResource("Curve_jk5g7")
damage_reduction_curve = SubResource("Curve_bwg3m") damage_reduction_curve = SubResource("Curve_bwg3m")
torso_total_damage = 100 torso_pellet_damage = 6
head_total_damage = 150 head_pellet_damage = 24
limb_total_damage = 70 limb_pellet_damage = 6
arc = 0.08726646259971647 pellet_spread = NodePath("../PelletSpread")
max_pellets = 30
min_pellets = 30
shoot_distance = 40.0 shoot_distance = 40.0
fire_timer = NodePath("../FireTimer") fire_timer = NodePath("../FireTimer")
@ -67,3 +72,9 @@ one_shot = true
[node name="MultiplayerSynchronizer" type="MultiplayerSynchronizer" parent="."] [node name="MultiplayerSynchronizer" type="MultiplayerSynchronizer" parent="."]
replication_config = SubResource("SceneReplicationConfig_bwg3m") replication_config = SubResource("SceneReplicationConfig_bwg3m")
[node name="PelletSpread" type="Path2D" parent="."]
position = Vector2(640, 360)
curve = SubResource("Curve2D_0fc4q")
script = ExtResource("6_a53f6")
metadata/_custom_type_script = "uid://ryxe3lxtvpk4"

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View file

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cs1dapnsaw2vw"
path="res://.godot/imported/icon.png-0bb35b0bcb159408ed12f260c09d8538.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://weapons/gun/pellet_spread/icon.png"
dest_files=["res://.godot/imported/icon.png-0bb35b0bcb159408ed12f260c09d8538.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

View file

@ -0,0 +1,13 @@
@icon("res://weapons/gun/pellet_spread/icon.png")
class_name PelletSpread extends Path2D
func get_dots() -> PackedVector2Array:
var result: PackedVector2Array
for i in curve.point_count:
result.append(curve.get_point_position(i))
for i in range(len(result)):
result[i] += get_viewport_rect().size/2.0
return result

View file

@ -0,0 +1 @@
uid://ryxe3lxtvpk4

View file

@ -0,0 +1,22 @@
@tool
extends PelletSpread
class_name PelletSpreadRandom
const ASPECT = 1.7777777777777777
@export var random_amount: int
@export_range(0,89,0.1,"radians_as_degrees") var radius: float
@export var aspect_ratio: float = 1.7777777777777777
@export_tool_button("Randomize points") var randomize_button = randomize_points
func randomize_points() -> void:
curve.clear_points()
var viewport_aspect_trasformation = Vector2(ASPECT,1)
var custom_aspect_transformation = Vector2(aspect_ratio,1./aspect_ratio)
var transformation_vector = get_viewport_rect().size / viewport_aspect_trasformation /PI
for i in range(random_amount):
var unscaled_position = Vector2(randf_range(-radius,radius),randf_range(-radius,radius))
var scaled_position = unscaled_position*transformation_vector
curve.add_point(scaled_position)

View file

@ -0,0 +1 @@
uid://b3cvfkvvc5c3g

View file

@ -5,12 +5,10 @@ extends WeaponState
@export var damage_reduction_curve: Curve @export var damage_reduction_curve: Curve
@export var emptyable: bool @export var emptyable: bool
@export var torso_total_damage: int @export var torso_pellet_damage: int
@export var head_total_damage: int @export var head_pellet_damage: int
@export var limb_total_damage: int @export var limb_pellet_damage: int
@export_range(0,179,0.01,"radians_as_degrees") var arc: float @export var pellet_spread: PelletSpread
@export_range(1,20,1,"or_greater") var max_pellets: int = 1
@export_range(1,20,1,"or_greater") var min_pellets: int = 1
@export var shoot_distance: float = 100 @export var shoot_distance: float = 100
@export var fire_timer: Timer @export var fire_timer: Timer
@ -44,8 +42,7 @@ func fire() -> void:
machine.animation_player.play(with_morphems("shoot")) machine.animation_player.play(with_morphems("shoot"))
if is_multiplayer_authority(): if is_multiplayer_authority():
var pellets: int = randi_range(min_pellets,max_pellets) Session.shoot_pellets(int(machine.player.name),limb_pellet_damage,torso_pellet_damage,head_pellet_damage,shoot_distance,pellet_spread.get_dots(),damage_reduction_curve)
Session.shoot_pellets(int(machine.player.name),pellets,limb_total_damage,torso_total_damage,head_total_damage,shoot_distance,arc,damage_reduction_curve)
machine.player.get_node("ShootAudio").multiplayer_play() machine.player.get_node("ShootAudio").multiplayer_play()
fire_timer.start() fire_timer.start()