Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| db477b4c48 | |||
| 4a5264c5b0 | |||
| ad48f38ca5 | |||
| f0c95dcfd2 | |||
| d060ac449d | |||
| 87060b0b71 | |||
| 638e109d8b | |||
| 4c0e334575 | |||
| e270f34150 | |||
| 20ca43f928 | |||
| aae57c63bd | |||
| 0994a55486 | |||
| 82216bfa64 | |||
| d5098c61e1 | |||
| 194aad8f83 | |||
| 222dcaebb3 | |||
| 0aa29d33e4 | |||
| 6a08487c4c | |||
| f20d532add | |||
| 705b068ed2 | |||
| 3465922be4 | |||
| 46ff83325f | |||
| f6d69545c9 | |||
| 2452aba0d7 | |||
| 3c3251fa7a | |||
| d02b112d99 | |||
| 2582cb1b0d | |||
| 9ea98aa7b8 |
@@ -28,3 +28,4 @@ server/build/
|
|||||||
# Secrets (operator must create per deployment)
|
# Secrets (operator must create per deployment)
|
||||||
server/data/rcon_password.cfg
|
server/data/rcon_password.cfg
|
||||||
build/
|
build/
|
||||||
|
build/
|
||||||
|
|||||||
@@ -0,0 +1,248 @@
|
|||||||
|
[gd_scene load_steps=12 format=3]
|
||||||
|
|
||||||
|
; =============================================================================
|
||||||
|
; test_range.tscn — Greybox Test Map
|
||||||
|
; =============================================================================
|
||||||
|
; A simple open-area test map for validating movement, shooting, and networking.
|
||||||
|
;
|
||||||
|
; Layout:
|
||||||
|
; - 80×80 open area with flat grey floor
|
||||||
|
; - Low platform (center, 1 unit high, gold)
|
||||||
|
; - Medium platform (east, 2 units high, gold)
|
||||||
|
; - High platform (north-west, 3 units high, red)
|
||||||
|
; - Ramp from ground to low platform (yellow)
|
||||||
|
; - Enclosure/room (east) with doorway for indoor testing (blue-grey walls)
|
||||||
|
; - Spawn point (Marker3D) with group 'spawn_points'
|
||||||
|
; - DirectionalLight3D + WorldEnvironment
|
||||||
|
;
|
||||||
|
; Total geometry: ~132 tris (well under 500 budget)
|
||||||
|
; =============================================================================
|
||||||
|
|
||||||
|
[sub_resource type="Environment" id="1"]
|
||||||
|
background_mode = 0
|
||||||
|
tonemap_mode = 0
|
||||||
|
glow_enabled = false
|
||||||
|
ambient_light_color = Color(0.25, 0.25, 0.3, 1.0)
|
||||||
|
ambient_light_energy = 0.4
|
||||||
|
ambient_light_sky_contribution = 0.0
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="2"]
|
||||||
|
albedo_color = Color(0.35, 0.35, 0.35, 1.0)
|
||||||
|
resource_name = "grey_floor"
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="3"]
|
||||||
|
albedo_color = Color(0.8, 0.6, 0.2, 1.0)
|
||||||
|
resource_name = "gold_platform"
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="4"]
|
||||||
|
albedo_color = Color(0.5, 0.5, 0.6, 1.0)
|
||||||
|
resource_name = "bluegrey_wall"
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="5"]
|
||||||
|
albedo_color = Color(0.9, 0.2, 0.2, 1.0)
|
||||||
|
resource_name = "red_high"
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="6"]
|
||||||
|
albedo_color = Color(0.3, 0.4, 0.3, 1.0)
|
||||||
|
resource_name = "green_floor"
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="7"]
|
||||||
|
albedo_color = Color(0.7, 0.7, 0.3, 1.0)
|
||||||
|
resource_name = "yellow_ramp"
|
||||||
|
|
||||||
|
[sub_resource type="BoxShape3D" id="8"]
|
||||||
|
size = Vector3(8, 4, 4)
|
||||||
|
|
||||||
|
[sub_resource type="BoxShape3D" id="9"]
|
||||||
|
size = Vector3(8, 4, 4)
|
||||||
|
|
||||||
|
|
||||||
|
; === Root Node ===
|
||||||
|
|
||||||
|
[node name="TestRange" type="Node3D"]
|
||||||
|
|
||||||
|
|
||||||
|
; === Lighting ===
|
||||||
|
|
||||||
|
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
|
||||||
|
environment = SubResource("1")
|
||||||
|
|
||||||
|
[node name="SunLight" type="DirectionalLight3D" parent="."]
|
||||||
|
transform = Transform3D(0.866, 0, -0.5, -0.354, 0.707, -0.612, 0.354, 0.707, 0.612, 0, 8, 0)
|
||||||
|
light_energy = 1.5
|
||||||
|
light_indirect_energy = 0.8
|
||||||
|
light_color = Color(1.0, 0.95, 0.9, 1.0)
|
||||||
|
shadow_enabled = true
|
||||||
|
directional_shadow_max_distance = 60.0
|
||||||
|
directional_shadow_split_1 = 0.1
|
||||||
|
directional_shadow_split_2 = 0.3
|
||||||
|
directional_shadow_split_3 = 0.6
|
||||||
|
directional_shadow_blend_splits = true
|
||||||
|
|
||||||
|
|
||||||
|
; === Spawn Points ===
|
||||||
|
|
||||||
|
[node name="SpawnPoint" type="Marker3D" parent="."]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -30, 0.5, 0)
|
||||||
|
groups = ["spawn_points"]
|
||||||
|
|
||||||
|
|
||||||
|
; === CT Spawn Points (Counter-Terrorist) ===
|
||||||
|
|
||||||
|
[node name="CTSpawn_01" type="Marker3D" parent="."]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -30, 0.5, -10)
|
||||||
|
groups = ["spawn_points_ct"]
|
||||||
|
|
||||||
|
[node name="CTSpawn_02" type="Marker3D" parent="."]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -25, 0.5, -15)
|
||||||
|
groups = ["spawn_points_ct"]
|
||||||
|
|
||||||
|
|
||||||
|
; === T Spawn Points (Terrorist) ===
|
||||||
|
|
||||||
|
[node name="TSpawn_01" type="Marker3D" parent="."]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 25, 0.5, 25)
|
||||||
|
groups = ["spawn_points_t"]
|
||||||
|
|
||||||
|
[node name="TSpawn_02" type="Marker3D" parent="."]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 30, 0.5, 20)
|
||||||
|
groups = ["spawn_points_t"]
|
||||||
|
|
||||||
|
|
||||||
|
; =============================================================================
|
||||||
|
; Bomb Sites
|
||||||
|
; =============================================================================
|
||||||
|
; BombsiteA — south-west area, 8×4m zone
|
||||||
|
; BombsiteB — north-east area, 8×4m zone
|
||||||
|
; Each has a CollisionShape3D (BoxShape3D) for overlap detection
|
||||||
|
; and a Marker3D child named "PlantPosition" marking the plant location.
|
||||||
|
|
||||||
|
; --- Bombsite A ---
|
||||||
|
|
||||||
|
|
||||||
|
[node name="BombsiteA" type="Area3D" parent="."]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -20, 1.0, -5)
|
||||||
|
collision_layer = 0
|
||||||
|
collision_mask = 0
|
||||||
|
groups = ["bomb_sites"]
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="BombsiteA"]
|
||||||
|
shape = SubResource("8")
|
||||||
|
|
||||||
|
[node name="PlantPosition" type="Marker3D" parent="BombsiteA"]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2, 0, -1)
|
||||||
|
|
||||||
|
; --- Bombsite B ---
|
||||||
|
|
||||||
|
|
||||||
|
[node name="BombsiteB" type="Area3D" parent="."]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 15, 1.0, 20)
|
||||||
|
collision_layer = 0
|
||||||
|
collision_mask = 0
|
||||||
|
groups = ["bomb_sites"]
|
||||||
|
|
||||||
|
[node name="PlantPosition" type="Marker3D" parent="BombsiteB"]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 2)
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="BombsiteB"]
|
||||||
|
shape = SubResource("9")
|
||||||
|
|
||||||
|
|
||||||
|
; === Open Area Floor (80×80) ===
|
||||||
|
|
||||||
|
[node name="Floor" type="CSGBox3D" parent="."]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.25, 0)
|
||||||
|
size = Vector3(80, 0.5, 80)
|
||||||
|
material = SubResource("2")
|
||||||
|
use_collision = true
|
||||||
|
|
||||||
|
|
||||||
|
; === Low Platform (center, 1 unit high) ===
|
||||||
|
; 8×8 platform, top at y=2, bottom at y=0, centered at origin
|
||||||
|
|
||||||
|
[node name="LowPlatform" type="CSGBox3D" parent="."]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.0, 0)
|
||||||
|
size = Vector3(8, 2, 8)
|
||||||
|
material = SubResource("3")
|
||||||
|
use_collision = true
|
||||||
|
|
||||||
|
|
||||||
|
; === Medium Platform (east, 2 units high) ===
|
||||||
|
; 6×6 platform, top at y=3, bottom at y=1 — jump-up from low platform height
|
||||||
|
|
||||||
|
[node name="MediumPlatform" type="CSGBox3D" parent="."]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 15, 2.0, 10)
|
||||||
|
size = Vector3(6, 2, 6)
|
||||||
|
material = SubResource("3")
|
||||||
|
use_collision = true
|
||||||
|
|
||||||
|
|
||||||
|
; === High Platform (north-west, 3 units high) ===
|
||||||
|
; 3×3 small platform, top at y=4 — requires sprint-jump to reach
|
||||||
|
|
||||||
|
[node name="HighPlatform" type="CSGBox3D" parent="."]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -20, 3.0, -15)
|
||||||
|
size = Vector3(3, 2, 3)
|
||||||
|
material = SubResource("5")
|
||||||
|
use_collision = true
|
||||||
|
|
||||||
|
|
||||||
|
; === Ramp (south of center, leads ground → low platform top) ===
|
||||||
|
; Tilted ~20° around X axis, 6 units long along Z.
|
||||||
|
; South end near ground, north end meets low platform top (y=2).
|
||||||
|
|
||||||
|
[node name="Ramp" type="CSGBox3D" parent="."]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 0.940, -0.342, 0, 0.342, 0.940, 0, 1.0, 5)
|
||||||
|
size = Vector3(6, 0.2, 6)
|
||||||
|
material = SubResource("7")
|
||||||
|
use_collision = true
|
||||||
|
|
||||||
|
|
||||||
|
; =============================================================================
|
||||||
|
; Enclosure — Indoor Testing Room
|
||||||
|
; =============================================================================
|
||||||
|
; 12×12 interior room, 4 units tall, with a 2-unit doorway on the south face.
|
||||||
|
; Centered at (30, 0, 30).
|
||||||
|
|
||||||
|
[node name="Enclosure" type="Node3D" parent="."]
|
||||||
|
|
||||||
|
[node name="RoomFloor" type="CSGBox3D" parent="Enclosure"]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 30, 0.25, 30)
|
||||||
|
size = Vector3(12, 0.5, 12)
|
||||||
|
material = SubResource("6")
|
||||||
|
use_collision = true
|
||||||
|
|
||||||
|
; North wall (z = 24)
|
||||||
|
[node name="Wall_N" type="CSGBox3D" parent="Enclosure"]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 30, 2.0, 24.25)
|
||||||
|
size = Vector3(12, 4, 0.5)
|
||||||
|
material = SubResource("4")
|
||||||
|
use_collision = true
|
||||||
|
|
||||||
|
; South wall left segment (doorway gap from x=29 to x=31)
|
||||||
|
[node name="Wall_S_Left" type="CSGBox3D" parent="Enclosure"]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 26.5, 2.0, 35.75)
|
||||||
|
size = Vector3(5, 4, 0.5)
|
||||||
|
material = SubResource("4")
|
||||||
|
use_collision = true
|
||||||
|
|
||||||
|
; South wall right segment
|
||||||
|
[node name="Wall_S_Right" type="CSGBox3D" parent="Enclosure"]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 33.5, 2.0, 35.75)
|
||||||
|
size = Vector3(5, 4, 0.5)
|
||||||
|
material = SubResource("4")
|
||||||
|
use_collision = true
|
||||||
|
|
||||||
|
; West wall (x = 24)
|
||||||
|
[node name="Wall_W" type="CSGBox3D" parent="Enclosure"]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 24.25, 2.0, 30)
|
||||||
|
size = Vector3(0.5, 4, 12)
|
||||||
|
material = SubResource("4")
|
||||||
|
use_collision = true
|
||||||
|
|
||||||
|
; East wall (x = 36)
|
||||||
|
[node name="Wall_E" type="CSGBox3D" parent="Enclosure"]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 35.75, 2.0, 30)
|
||||||
|
size = Vector3(0.5, 4, 12)
|
||||||
|
material = SubResource("4")
|
||||||
|
use_collision = true
|
||||||
@@ -0,0 +1,160 @@
|
|||||||
|
@tool
|
||||||
|
extends Node
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# art_kit.gd — Modular Art Kit Factory
|
||||||
|
# =============================================================================
|
||||||
|
# Provides factory methods for spawning modular environment pieces and a
|
||||||
|
# preview catalogue for map builders.
|
||||||
|
#
|
||||||
|
# Each piece is a standalone .tscn under pieces/ with:
|
||||||
|
# - CSG shapes (Box3D, Cylinder3D, Polygon3D, Combiner3D)
|
||||||
|
# - Solid-color StandardMaterial3D placeholders (roughness 0.8, metallic 0.0)
|
||||||
|
# - Collision enabled (use_collision = true or StaticBody3D + CollisionShape3D)
|
||||||
|
# - < 200 tris each
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# var piece = ArtKit.spawn_piece("crate", parent_node)
|
||||||
|
# var cat = ArtKit.preview_catalogue()
|
||||||
|
# var stack = ArtKit.random_crate_layout(3, 2) # returns parent Node3D
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
const PIECES_DIR := "res://client/assets/scenes/modular/pieces/"
|
||||||
|
|
||||||
|
# Catalogue definition: name, description, filename (without .tscn)
|
||||||
|
const CATALOGUE: Array[Dictionary] = [
|
||||||
|
{
|
||||||
|
"name": "floor_tile",
|
||||||
|
"description": "2×2×0.2m concrete slab — grey",
|
||||||
|
"file": "floor_tile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "wall_segment",
|
||||||
|
"description": "4×0.2×3m wall panel — blue-grey",
|
||||||
|
"file": "wall_segment"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "corner_wall",
|
||||||
|
"description": "L-shaped corner piece (2m each leg) — blue-grey",
|
||||||
|
"file": "corner_wall"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "pillar",
|
||||||
|
"description": "0.3×3×0.3m column — dark grey",
|
||||||
|
"file": "pillar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "crate",
|
||||||
|
"description": "1×1×1m storage box — brown/tan",
|
||||||
|
"file": "crate"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "barrel",
|
||||||
|
"description": "0.6m radius × 1m tall cylinder — red",
|
||||||
|
"file": "barrel"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cover_wall",
|
||||||
|
"description": "2×0.2×1.3m low wall (crouch-height cover) — grey",
|
||||||
|
"file": "cover_wall"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ramp",
|
||||||
|
"description": "2×2m, 30° incline ramp — yellow",
|
||||||
|
"file": "ramp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "stairs",
|
||||||
|
"description": "3-step staircase (2m wide, 0.25m rise per step) — grey",
|
||||||
|
"file": "stairs"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "window_frame",
|
||||||
|
"description": "4×3m wall with 2×2m opening — blue-grey",
|
||||||
|
"file": "window_frame"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Public API
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
## Spawns a piece by name, adds it as a child of `parent`, and returns it.
|
||||||
|
## Returns null if the piece name is unknown or the scene fails to load.
|
||||||
|
static func spawn_piece(piece_name: String, parent: Node) -> Node3D:
|
||||||
|
var entry := _find_entry(piece_name)
|
||||||
|
if entry.is_empty():
|
||||||
|
push_error("ArtKit: Unknown piece '%s'. Use preview_catalogue() to see available pieces." % piece_name)
|
||||||
|
return null
|
||||||
|
|
||||||
|
var path := PIECES_DIR + entry.file + ".tscn"
|
||||||
|
var scene := load(path)
|
||||||
|
if scene == null:
|
||||||
|
push_error("ArtKit: Failed to load scene at '%s'." % path)
|
||||||
|
return null
|
||||||
|
|
||||||
|
var instance: Node3D = scene.instantiate()
|
||||||
|
parent.add_child(instance)
|
||||||
|
instance.owner = parent if not Engine.is_editor_hint() else _get_editor_owner(parent)
|
||||||
|
return instance
|
||||||
|
|
||||||
|
|
||||||
|
## Returns an array of { name, description, path } for all available pieces.
|
||||||
|
static func preview_catalogue() -> Array[Dictionary]:
|
||||||
|
var result: Array[Dictionary] = []
|
||||||
|
for entry in CATALOGUE:
|
||||||
|
result.append({
|
||||||
|
"name": entry.name,
|
||||||
|
"description": entry.description,
|
||||||
|
"path": PIECES_DIR + entry.file + ".tscn"
|
||||||
|
})
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
## Generates a random stack of crates for quick testing layouts.
|
||||||
|
## `width` — number of crates along X (default 3)
|
||||||
|
## `height` — number of crates stacked vertically (default 2)
|
||||||
|
## Returns a Node3D containing the crate instances.
|
||||||
|
static func random_crate_layout(width: int = 3, height: int = 2) -> Node3D:
|
||||||
|
var root := Node3D.new()
|
||||||
|
root.name = "CrateLayout_%dx%d" % [width, height]
|
||||||
|
|
||||||
|
var crate_scene := load(PIECES_DIR + "crate.tscn")
|
||||||
|
if crate_scene == null:
|
||||||
|
push_error("ArtKit: Could not load crate scene.")
|
||||||
|
return root
|
||||||
|
|
||||||
|
for y in range(height):
|
||||||
|
for x in range(width):
|
||||||
|
# Add slight random offset for natural look (±0.05m)
|
||||||
|
var offset_x := randf_range(-0.05, 0.05)
|
||||||
|
var offset_z := randf_range(-0.05, 0.05)
|
||||||
|
# Full rotation in 90° increments
|
||||||
|
var rot_y := randi() % 4 * 90.0
|
||||||
|
|
||||||
|
var crate: Node3D = crate_scene.instantiate()
|
||||||
|
crate.position = Vector3(x * 1.0 + offset_x, y * 1.0 + 0.5, offset_z)
|
||||||
|
crate.rotation_degrees = Vector3(0, rot_y, 0)
|
||||||
|
root.add_child(crate)
|
||||||
|
|
||||||
|
return root
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Internal helpers
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static func _find_entry(piece_name: String) -> Dictionary:
|
||||||
|
for entry in CATALOGUE:
|
||||||
|
if entry.name == piece_name:
|
||||||
|
return entry
|
||||||
|
return {}
|
||||||
|
|
||||||
|
|
||||||
|
## Returns the editor's top-level owner so new nodes are treated as part of the scene.
|
||||||
|
static func _get_editor_owner(node: Node) -> Node:
|
||||||
|
var owner = node
|
||||||
|
while owner and owner.owner:
|
||||||
|
owner = owner.owner
|
||||||
|
return owner
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://dnopn0wj58j83
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://c6dxl1qhan4yl
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
[gd_scene load_steps=2 format=3]
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="1"]
|
||||||
|
albedo_color = Color(0.7, 0.15, 0.1, 1.0)
|
||||||
|
roughness = 0.6
|
||||||
|
metallic = 0.2
|
||||||
|
resource_name = "red_barrel"
|
||||||
|
|
||||||
|
[node name="Barrel" type="CSGCylinder3D"]
|
||||||
|
radius = 0.6
|
||||||
|
height = 1.0
|
||||||
|
material = SubResource("1")
|
||||||
|
use_collision = true
|
||||||
|
slices = 16
|
||||||
|
visibility_range_end = 30.0
|
||||||
|
visibility_range_end_margin = 3.0
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
[gd_scene load_steps=2 format=3]
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="1"]
|
||||||
|
albedo_color = Color(0.35, 0.4, 0.5, 1.0)
|
||||||
|
roughness = 0.8
|
||||||
|
metallic = 0.0
|
||||||
|
resource_name = "bluegrey_corner"
|
||||||
|
|
||||||
|
[node name="CornerWall" type="CSGCombiner3D"]
|
||||||
|
use_collision = false
|
||||||
|
visibility_range_end = 50.0
|
||||||
|
visibility_range_end_margin = 5.0
|
||||||
|
|
||||||
|
[node name="WallA" type="CSGBox3D" parent="CornerWall"]
|
||||||
|
operation = 0
|
||||||
|
size = Vector3(2, 3, 0.2)
|
||||||
|
material = SubResource("1")
|
||||||
|
use_collision = true
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.1)
|
||||||
|
|
||||||
|
[node name="WallB" type="CSGBox3D" parent="CornerWall"]
|
||||||
|
operation = 0
|
||||||
|
size = Vector3(0.2, 3, 2)
|
||||||
|
material = SubResource("1")
|
||||||
|
use_collision = true
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.1, 0, 0)
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
[gd_scene load_steps=2 format=3]
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="1"]
|
||||||
|
albedo_color = Color(0.4, 0.4, 0.4, 1.0)
|
||||||
|
roughness = 0.8
|
||||||
|
metallic = 0.0
|
||||||
|
resource_name = "grey_cover"
|
||||||
|
|
||||||
|
[node name="CoverWall" type="CSGBox3D"]
|
||||||
|
size = Vector3(2, 1.3, 0.2)
|
||||||
|
material = SubResource("1")
|
||||||
|
use_collision = true
|
||||||
|
visibility_range_end = 40.0
|
||||||
|
visibility_range_end_margin = 5.0
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
[gd_scene load_steps=2 format=3]
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="1"]
|
||||||
|
albedo_color = Color(0.55, 0.35, 0.15, 1.0)
|
||||||
|
roughness = 0.85
|
||||||
|
metallic = 0.0
|
||||||
|
resource_name = "brown_crate"
|
||||||
|
|
||||||
|
[node name="Crate" type="CSGBox3D"]
|
||||||
|
size = Vector3(1, 1, 1)
|
||||||
|
material = SubResource("1")
|
||||||
|
use_collision = true
|
||||||
|
visibility_range_end = 40.0
|
||||||
|
visibility_range_end_margin = 5.0
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
[gd_scene load_steps=2 format=3]
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="1"]
|
||||||
|
albedo_color = Color(0.5, 0.5, 0.5, 1.0)
|
||||||
|
roughness = 0.8
|
||||||
|
metallic = 0.0
|
||||||
|
resource_name = "concrete_grey"
|
||||||
|
|
||||||
|
[node name="FloorTile" type="CSGBox3D"]
|
||||||
|
size = Vector3(2, 0.2, 2)
|
||||||
|
material = SubResource("1")
|
||||||
|
use_collision = true
|
||||||
|
visibility_range_end = 60.0
|
||||||
|
visibility_range_end_margin = 10.0
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
[gd_scene load_steps=2 format=3]
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="1"]
|
||||||
|
albedo_color = Color(0.2, 0.2, 0.22, 1.0)
|
||||||
|
roughness = 0.8
|
||||||
|
metallic = 0.0
|
||||||
|
resource_name = "darkgrey_pillar"
|
||||||
|
|
||||||
|
[node name="Pillar" type="CSGBox3D"]
|
||||||
|
size = Vector3(0.3, 3, 0.3)
|
||||||
|
material = SubResource("1")
|
||||||
|
use_collision = true
|
||||||
|
visibility_range_end = 30.0
|
||||||
|
visibility_range_end_margin = 3.0
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
[gd_scene load_steps=2 format=3]
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="1"]
|
||||||
|
albedo_color = Color(0.7, 0.7, 0.3, 1.0)
|
||||||
|
roughness = 0.8
|
||||||
|
metallic = 0.0
|
||||||
|
resource_name = "yellow_ramp"
|
||||||
|
|
||||||
|
[node name="Ramp" type="CSGPolygon3D"]
|
||||||
|
polygon = PackedVector2Array(0, 0, 2, 0, 2, 1.155)
|
||||||
|
depth = 2.0
|
||||||
|
material = SubResource("1")
|
||||||
|
use_collision = true
|
||||||
|
smooth_faces = true
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
[gd_scene load_steps=2 format=3]
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="1"]
|
||||||
|
albedo_color = Color(0.45, 0.45, 0.45, 1.0)
|
||||||
|
roughness = 0.8
|
||||||
|
metallic = 0.0
|
||||||
|
resource_name = "grey_stairs"
|
||||||
|
|
||||||
|
[node name="Stairs" type="CSGCombiner3D"]
|
||||||
|
use_collision = false
|
||||||
|
visibility_range_end = 40.0
|
||||||
|
visibility_range_end_margin = 5.0
|
||||||
|
|
||||||
|
[node name="Step1" type="CSGBox3D" parent="Stairs"]
|
||||||
|
operation = 0
|
||||||
|
size = Vector3(2, 0.25, 0.5)
|
||||||
|
material = SubResource("1")
|
||||||
|
use_collision = true
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.125, 0.75)
|
||||||
|
|
||||||
|
[node name="Step2" type="CSGBox3D" parent="Stairs"]
|
||||||
|
operation = 0
|
||||||
|
size = Vector3(2, 0.25, 0.5)
|
||||||
|
material = SubResource("1")
|
||||||
|
use_collision = true
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.375, 0.25)
|
||||||
|
|
||||||
|
[node name="Step3" type="CSGBox3D" parent="Stairs"]
|
||||||
|
operation = 0
|
||||||
|
size = Vector3(2, 0.25, 0.5)
|
||||||
|
material = SubResource("1")
|
||||||
|
use_collision = true
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.625, -0.25)
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
[gd_scene load_steps=2 format=3]
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="1"]
|
||||||
|
albedo_color = Color(0.35, 0.4, 0.5, 1.0)
|
||||||
|
roughness = 0.8
|
||||||
|
metallic = 0.0
|
||||||
|
resource_name = "bluegrey_wall"
|
||||||
|
|
||||||
|
[node name="WallSegment" type="CSGBox3D"]
|
||||||
|
size = Vector3(4, 3, 0.2)
|
||||||
|
material = SubResource("1")
|
||||||
|
use_collision = true
|
||||||
|
visibility_range_end = 50.0
|
||||||
|
visibility_range_end_margin = 5.0
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
[gd_scene load_steps=2 format=3]
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="1"]
|
||||||
|
albedo_color = Color(0.35, 0.4, 0.5, 1.0)
|
||||||
|
roughness = 0.8
|
||||||
|
metallic = 0.0
|
||||||
|
resource_name = "bluegrey_window"
|
||||||
|
|
||||||
|
[node name="WindowFrame" type="CSGCombiner3D"]
|
||||||
|
use_collision = false
|
||||||
|
visibility_range_end = 40.0
|
||||||
|
visibility_range_end_margin = 5.0
|
||||||
|
|
||||||
|
[node name="MainWall" type="CSGBox3D" parent="WindowFrame"]
|
||||||
|
operation = 0
|
||||||
|
size = Vector3(4, 3, 0.2)
|
||||||
|
material = SubResource("1")
|
||||||
|
use_collision = true
|
||||||
|
|
||||||
|
[node name="WindowCutout" type="CSGBox3D" parent="WindowFrame"]
|
||||||
|
operation = 1
|
||||||
|
size = Vector3(2, 2, 0.25)
|
||||||
|
use_collision = true
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://bjtf5jiedmwx8
|
||||||
@@ -88,10 +88,19 @@ var _input_sequence: int = 0
|
|||||||
## Cached input dictionary (avoids alloc per frame).
|
## Cached input dictionary (avoids alloc per frame).
|
||||||
var _input_dict: Dictionary = {}
|
var _input_dict: Dictionary = {}
|
||||||
|
|
||||||
|
## Prediction controller reference (set by ClientPrediction system).
|
||||||
|
## When non-null and prediction_enabled, the controller uses client-side
|
||||||
|
## prediction with local movement for instant feedback instead of
|
||||||
|
## reading position from the SimulationServer entity directly.
|
||||||
|
var _prediction: Node = null
|
||||||
|
|
||||||
## Mouse capture state.
|
## Mouse capture state.
|
||||||
var _mouse_captured: bool = false
|
var _mouse_captured: bool = false
|
||||||
var _mouse_clicked_this_frame: bool = false
|
var _mouse_clicked_this_frame: bool = false
|
||||||
|
|
||||||
|
## Weapon manager reference.
|
||||||
|
var _weapon: WeaponManager = null
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Node references (set in _ready)
|
# Node references (set in _ready)
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
@@ -152,6 +161,12 @@ func _ready() -> void:
|
|||||||
_crouch_current = 0.0
|
_crouch_current = 0.0
|
||||||
_update_crouch(0.0)
|
_update_crouch(0.0)
|
||||||
|
|
||||||
|
# Find weapon manager child
|
||||||
|
for child in get_children():
|
||||||
|
if child is WeaponManager:
|
||||||
|
_weapon = child
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
func _input(event: InputEvent) -> void:
|
func _input(event: InputEvent) -> void:
|
||||||
# Mouse look
|
# Mouse look
|
||||||
@@ -184,6 +199,12 @@ func _unhandled_input(event: InputEvent) -> void:
|
|||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
func _physics_process(delta: float) -> void:
|
func _physics_process(delta: float) -> void:
|
||||||
|
# PREDICTION HOOK: capture pre-input state snapshot.
|
||||||
|
# Must be called BEFORE any input processing or movement so the
|
||||||
|
# snapshot represents the state at the start of this tick.
|
||||||
|
if _prediction and _prediction.prediction_enabled:
|
||||||
|
_prediction.on_before_tick()
|
||||||
|
|
||||||
# 1. Capture input state
|
# 1. Capture input state
|
||||||
var input_dir := _get_move_direction()
|
var input_dir := _get_move_direction()
|
||||||
var jump_pressed := Input.is_action_just_pressed(&"jump")
|
var jump_pressed := Input.is_action_just_pressed(&"jump")
|
||||||
@@ -227,34 +248,60 @@ func _physics_process(delta: float) -> void:
|
|||||||
if _camera:
|
if _camera:
|
||||||
_camera.rotation.x = _pitch
|
_camera.rotation.x = _pitch
|
||||||
|
|
||||||
# 6. Send input to simulation server
|
# 5b. Weapon fire with rate limiting via WeaponManager
|
||||||
if _server != null and entity_id >= 0:
|
var should_fire: bool = false
|
||||||
# Build input for SimulationServer (mutate cached dict to avoid alloc)
|
var time_since_engine_start: float = Engine.get_process_ticks() * get_physics_process_delta_time()
|
||||||
|
if _weapon:
|
||||||
|
should_fire = _weapon.try_fire(time_since_engine_start)
|
||||||
|
elif shoot_pressed:
|
||||||
|
# No weapon manager — fire every tick (unlimited)
|
||||||
|
should_fire = true
|
||||||
|
|
||||||
|
if _server != null:
|
||||||
|
if should_fire:
|
||||||
|
_server.fire_weapon(entity_id)
|
||||||
|
|
||||||
|
# 6. Build input dictionary (all modes — mutate cached dict to avoid alloc)
|
||||||
_input_dict["move_direction"] = input_dir
|
_input_dict["move_direction"] = input_dir
|
||||||
_input_dict["look_yaw"] = rad_to_deg(_yaw)
|
_input_dict["look_yaw"] = rad_to_deg(_yaw)
|
||||||
_input_dict["look_pitch"] = rad_to_deg(_pitch)
|
_input_dict["look_pitch"] = rad_to_deg(_pitch)
|
||||||
_input_dict["jump"] = jump_pressed
|
_input_dict["jump"] = jump_pressed
|
||||||
_input_dict["crouch"] = _crouch_active
|
_input_dict["crouch"] = _crouch_active
|
||||||
_input_dict["sprint"] = _sprint_active
|
_input_dict["sprint"] = _sprint_active
|
||||||
_input_dict["shoot"] = shoot_pressed
|
_input_dict["shoot"] = should_fire
|
||||||
_input_dict["aim"] = aim_pressed
|
_input_dict["aim"] = aim_pressed
|
||||||
_input_dict["input_sequence"] = _input_sequence
|
_input_dict["input_sequence"] = _input_sequence
|
||||||
|
|
||||||
|
# 6b. Route input to appropriate handler.
|
||||||
|
if _prediction and _prediction.prediction_enabled:
|
||||||
|
# Client prediction: input sending is handled by the prediction
|
||||||
|
# controller's on_after_tick() call at the end of this function.
|
||||||
|
pass
|
||||||
|
elif _server != null and entity_id >= 0:
|
||||||
|
# Listen server: send to local SimulationServer.
|
||||||
_server.apply_input(entity_id, _input_dict)
|
_server.apply_input(entity_id, _input_dict)
|
||||||
|
|
||||||
if shoot_pressed:
|
# Check for hit feedback from last tick
|
||||||
_server.fire_weapon(entity_id)
|
if Engine.has_singleton("SimulationServer") or _server:
|
||||||
|
var hit_result: Dictionary = _server.get_last_hit_result()
|
||||||
|
if hit_result.get("hit", false) and _weapon:
|
||||||
|
var hit_pos := Vector3.ZERO # approximate — we don't have exact world hit position from server yet
|
||||||
|
_weapon.on_hit_confirmed(hit_pos, hit_result.get("damage", 0.0), hit_result.get("killed", false))
|
||||||
|
|
||||||
_input_sequence += 1
|
_input_sequence += 1
|
||||||
|
|
||||||
# 7. Read server state back (for local simulation / listen server)
|
# 7. Update position.
|
||||||
# The SimulationServer.tick() call happens in the game manager / network layer.
|
# Architecture:
|
||||||
# Here we optionally read the entity's canonical position from the server.
|
# - Client prediction: do local CharacterBody3D movement (instant feedback),
|
||||||
# NOTE: On a dedicated client, position comes from the network replication
|
# the prediction controller handles reconciliation when authoritative
|
||||||
# layer (server snapshot), not from direct server entity access.
|
# server state arrives.
|
||||||
# On a listen server (host+client same process) or in standalone mode,
|
# - Listen server: read authoritative position from SimulationServer entity.
|
||||||
# reading position directly from the server entity is correct.
|
# - Standalone (no server): fallback CharacterBody3D movement.
|
||||||
if _server != null and entity_id >= 0:
|
if _prediction and _prediction.prediction_enabled:
|
||||||
|
# Client prediction path — local movement for instant feedback.
|
||||||
|
_move_local(input_dir, delta, jump_pressed)
|
||||||
|
elif _server != null and entity_id >= 0:
|
||||||
|
# Listen server: read from SimulationServer entity.
|
||||||
var entity = _server.get_entity(entity_id)
|
var entity = _server.get_entity(entity_id)
|
||||||
if entity != null and entity.is_alive():
|
if entity != null and entity.is_alive():
|
||||||
# Server position is ground truth — apply it to the visual body
|
# Server position is ground truth — apply it to the visual body
|
||||||
@@ -264,6 +311,12 @@ func _physics_process(delta: float) -> void:
|
|||||||
# Standalone mode: do local CharacterBody3D physics
|
# Standalone mode: do local CharacterBody3D physics
|
||||||
_move_local(input_dir, delta, jump_pressed)
|
_move_local(input_dir, delta, jump_pressed)
|
||||||
|
|
||||||
|
# PREDICTION HOOK: post-tick — send input to server via RPC.
|
||||||
|
# Must be called AFTER local movement so the prediction controller
|
||||||
|
# can send the input that produced this tick's movement.
|
||||||
|
if _prediction and _prediction.prediction_enabled:
|
||||||
|
_prediction.on_after_tick(_input_dict)
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Local movement (standalone / no-server fallback)
|
# Local movement (standalone / no-server fallback)
|
||||||
@@ -369,6 +422,13 @@ func set_entity_id(id: int) -> void:
|
|||||||
entity_id = id
|
entity_id = id
|
||||||
|
|
||||||
|
|
||||||
|
## Set the prediction controller for client-side prediction/reconciliation.
|
||||||
|
## The prediction node must have on_before_tick() / on_after_tick() methods.
|
||||||
|
## Typically a ClientPrediction instance added as a child or sibling.
|
||||||
|
func set_prediction(prediction_node: Node) -> void:
|
||||||
|
_prediction = prediction_node
|
||||||
|
|
||||||
|
|
||||||
## Get current crouch amount (0.0 = standing, 1.0 = fully crouched).
|
## Get current crouch amount (0.0 = standing, 1.0 = fully crouched).
|
||||||
func get_crouch_amount() -> float:
|
func get_crouch_amount() -> float:
|
||||||
return _crouch_current
|
return _crouch_current
|
||||||
@@ -399,3 +459,15 @@ func reset_pose() -> void:
|
|||||||
_crouch_current = 0.0
|
_crouch_current = 0.0
|
||||||
_crouch_target = 0.0
|
_crouch_target = 0.0
|
||||||
_update_crouch(0.0)
|
_update_crouch(0.0)
|
||||||
|
|
||||||
|
|
||||||
|
## Get the look direction as a normalized Vector3 in world space.
|
||||||
|
## Uses the current yaw/pitch to compute a forward vector.
|
||||||
|
func get_look_direction() -> Vector3:
|
||||||
|
var yaw_rad: float = _yaw
|
||||||
|
var pitch_rad: float = _pitch
|
||||||
|
return Vector3(
|
||||||
|
cos(pitch_rad) * sin(yaw_rad),
|
||||||
|
-sin(pitch_rad),
|
||||||
|
cos(pitch_rad) * cos(yaw_rad)
|
||||||
|
).normalized()
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://cpbvk1itjonm
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://bvkhxr1bv6lth
|
||||||
@@ -0,0 +1,293 @@
|
|||||||
|
## BombCarrier — Client-side bomb status UI and prompts.
|
||||||
|
##
|
||||||
|
## Attached to the local T player who carries the bomb.
|
||||||
|
## Provides visual feedback for:
|
||||||
|
## - Bomb status (planted/defusing/timer)
|
||||||
|
## - Direction indicator to planted bomb
|
||||||
|
## - "Hold E to defuse" prompt (CT, near bomb)
|
||||||
|
## - "Hold E to plant" prompt (T, in bombsite, LIVE phase)
|
||||||
|
##
|
||||||
|
## This script is a Node that should be added as a child of the local
|
||||||
|
## player's character node (FPSCharacterController) on the client side.
|
||||||
|
## It communicates with the server BombObjective via RPC or state sync.
|
||||||
|
|
||||||
|
extends Node
|
||||||
|
class_name BombCarrier
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Signals
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
## Emitted when the nearby interaction prompt changes.
|
||||||
|
signal prompt_changed(prompt_text: String, visible: bool)
|
||||||
|
|
||||||
|
## Emitted when bomb status UI should update.
|
||||||
|
signal bomb_status_updated(planted: bool, timer: float, defusing: bool, defuse_progress: float)
|
||||||
|
|
||||||
|
## Emitted when the bomb direction indicator should update.
|
||||||
|
signal bomb_direction_updated(bearing_degrees: float, distance: float)
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Exports
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
## The "Use/Interact" action name (matched in Input Map).
|
||||||
|
@export var interact_action: String = "interact"
|
||||||
|
|
||||||
|
## Interaction distance for planting (in Godot units).
|
||||||
|
@export var plant_distance: float = 2.0
|
||||||
|
|
||||||
|
## Interaction distance for defusing (in Godot units).
|
||||||
|
@export var defuse_distance: float = 3.0
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# State
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
## Whether this player has the bomb (T-side bomb carrier).
|
||||||
|
var has_bomb: bool = false
|
||||||
|
|
||||||
|
## Whether the bomb is currently planted.
|
||||||
|
var _bomb_planted: bool = false
|
||||||
|
|
||||||
|
## Position of the planted bomb (server-authoritative).
|
||||||
|
var _bomb_position: Vector3 = Vector3.ZERO
|
||||||
|
|
||||||
|
## Remaining bomb timer (received from server).
|
||||||
|
var _bomb_timer: float = 0.0
|
||||||
|
|
||||||
|
## Whether the local player is currently defusing.
|
||||||
|
var _is_defusing: bool = false
|
||||||
|
|
||||||
|
## Current defuse progress (0.0 to 1.0).
|
||||||
|
var _defuse_progress: float = 0.0
|
||||||
|
|
||||||
|
## Current prompt text to show.
|
||||||
|
var _current_prompt: String = ""
|
||||||
|
|
||||||
|
## Whether the prompt is currently visible.
|
||||||
|
var _prompt_visible: bool = false
|
||||||
|
|
||||||
|
## Whether we are inside a bombsite.
|
||||||
|
var _in_bombsite: bool = false
|
||||||
|
|
||||||
|
## Whether we are near the planted bomb.
|
||||||
|
var _near_planted_bomb: bool = false
|
||||||
|
|
||||||
|
## Whether the interact key is being held.
|
||||||
|
var _interact_held: bool = false
|
||||||
|
|
||||||
|
## Hold-down timer for plant/defuse (E key held long enough).
|
||||||
|
var _interact_hold_time: float = 0.0
|
||||||
|
|
||||||
|
## Time required to hold E to start action (for UX consistency).
|
||||||
|
var _interact_hold_duration: float = 0.0 # Immediate on press
|
||||||
|
|
||||||
|
## Reference to the local player's parent/character controller.
|
||||||
|
var _character_controller: Node = null
|
||||||
|
|
||||||
|
## Reference to the bomb objective on the server (for RPC calls).
|
||||||
|
## Set by the game manager after instantiation.
|
||||||
|
var bomb_objective_path: NodePath = NodePath()
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Lifecycle
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
_character_controller = get_parent()
|
||||||
|
if _character_controller == null:
|
||||||
|
push_warning("[BombCarrier] No parent node — prompts will not work")
|
||||||
|
|
||||||
|
# Try to set up the interact action if it doesn't exist
|
||||||
|
if not InputMap.has_action(interact_action):
|
||||||
|
var event := InputEventKey.new()
|
||||||
|
event.keycode = KEY_E
|
||||||
|
InputMap.add_action(interact_action)
|
||||||
|
InputMap.action_add_event(interact_action, event)
|
||||||
|
|
||||||
|
print("[BombCarrier] Initialised — has_bomb=%s" % has_bomb)
|
||||||
|
|
||||||
|
func _process(delta: float) -> void:
|
||||||
|
_update_interaction(delta)
|
||||||
|
_emit_status_updates()
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Public API — Server state sync
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
## Called by the game manager or network sync to update bomb state.
|
||||||
|
func sync_bomb_state(planted: bool, position: Vector3, timer: float,
|
||||||
|
defusing: bool, defuse_progress: float) -> void:
|
||||||
|
_bomb_planted = planted
|
||||||
|
_bomb_position = position
|
||||||
|
_bomb_timer = timer
|
||||||
|
_is_defusing = defusing
|
||||||
|
_defuse_progress = defuse_progress
|
||||||
|
|
||||||
|
## Set whether this player has the bomb (assigned by server).
|
||||||
|
func set_has_bomb(value: bool) -> void:
|
||||||
|
has_bomb = value
|
||||||
|
print("[BombCarrier] Has bomb: %s" % value)
|
||||||
|
|
||||||
|
## Set whether the local player is inside a bombsite Area3D.
|
||||||
|
## Called by the bombsite Area3D signal handlers on the client.
|
||||||
|
func set_in_bombsite(value: bool) -> void:
|
||||||
|
_in_bombsite = value
|
||||||
|
|
||||||
|
## Set whether the local player is near the planted bomb.
|
||||||
|
## Called by the bomb area proximity check.
|
||||||
|
func set_near_planted_bomb(value: bool) -> void:
|
||||||
|
_near_planted_bomb = value
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Public API — RPC calls to server
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
## Request to plant the bomb at the current position.
|
||||||
|
## Called when the T player presses E inside a bombsite with the bomb.
|
||||||
|
func request_plant() -> void:
|
||||||
|
if not has_bomb or not _in_bombsite:
|
||||||
|
return
|
||||||
|
if _bomb_planted:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Send plant request to server
|
||||||
|
# In real implementation, this would be an RPC call:
|
||||||
|
# _send_plant_request.rpc_id(1, _character_controller.global_position)
|
||||||
|
_send_plant_request(_character_controller.global_position)
|
||||||
|
|
||||||
|
## Request to start defusing the bomb.
|
||||||
|
## Called when the CT player presses E near the planted bomb.
|
||||||
|
func request_defuse() -> void:
|
||||||
|
if not _near_planted_bomb or not _bomb_planted:
|
||||||
|
return
|
||||||
|
if _is_defusing:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Send defuse request to server
|
||||||
|
# _send_defuse_request.rpc_id(1)
|
||||||
|
_send_defuse_request()
|
||||||
|
|
||||||
|
## Request to cancel defuse (when player moves or is interrupted).
|
||||||
|
func request_cancel_defuse() -> void:
|
||||||
|
if not _is_defusing:
|
||||||
|
return
|
||||||
|
_send_cancel_defuse()
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# RPC stubs (to be replaced with actual RPC calls)
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
func _send_plant_request(position: Vector3) -> void:
|
||||||
|
# Placeholder: in real implementation, send RPC to server
|
||||||
|
print("[BombCarrier] Plant request at (%.1f, %.1f, %.1f)" %
|
||||||
|
[position.x, position.y, position.z])
|
||||||
|
|
||||||
|
func _send_defuse_request() -> void:
|
||||||
|
# Placeholder: in real implementation, send RPC to server
|
||||||
|
print("[BombCarrier] Defuse request")
|
||||||
|
|
||||||
|
func _send_cancel_defuse() -> void:
|
||||||
|
# Placeholder: in real implementation, send RPC to server
|
||||||
|
print("[BombCarrier] Cancel defuse request")
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Internal — Interaction logic
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
func _update_interaction(delta: float) -> void:
|
||||||
|
var interact_pressed: bool = Input.is_action_pressed(interact_action)
|
||||||
|
var prompt_text: String = ""
|
||||||
|
var show_prompt: bool = false
|
||||||
|
|
||||||
|
# Determine what prompt to show
|
||||||
|
if _bomb_planted and _near_planted_bomb and not _is_defusing:
|
||||||
|
# CT player near planted bomb — defuse prompt
|
||||||
|
var team: int = _get_local_player_team()
|
||||||
|
if team == TeamData.Team.COUNTER_TERRORIST:
|
||||||
|
prompt_text = "Hold E to defuse"
|
||||||
|
show_prompt = true
|
||||||
|
|
||||||
|
elif has_bomb and _in_bombsite and not _bomb_planted:
|
||||||
|
# T player with bomb inside bombsite — plant prompt
|
||||||
|
if _is_round_live():
|
||||||
|
prompt_text = "Hold E to plant"
|
||||||
|
show_prompt = true
|
||||||
|
|
||||||
|
elif _bomb_planted and _is_defusing:
|
||||||
|
# Currently defusing — show progress
|
||||||
|
var progress_pct: int = int(_defuse_progress * 100.0)
|
||||||
|
prompt_text = "Defusing... %d%%" % progress_pct
|
||||||
|
show_prompt = true
|
||||||
|
|
||||||
|
# Handle interact hold
|
||||||
|
if interact_pressed and show_prompt:
|
||||||
|
if not _interact_held:
|
||||||
|
_interact_held = true
|
||||||
|
_interact_hold_time = 0.0
|
||||||
|
|
||||||
|
_interact_hold_time += delta
|
||||||
|
|
||||||
|
# Check if we should trigger the action
|
||||||
|
if _interact_hold_time >= _interact_hold_duration:
|
||||||
|
_interact_hold_time = 0.0
|
||||||
|
if prompt_text.contains("defuse"):
|
||||||
|
request_defuse()
|
||||||
|
elif prompt_text.contains("plant"):
|
||||||
|
request_plant()
|
||||||
|
else:
|
||||||
|
# Cancel any pending interaction
|
||||||
|
if _interact_held:
|
||||||
|
_interact_held = false
|
||||||
|
_interact_hold_time = 0.0
|
||||||
|
# If we were defusing and released, cancel
|
||||||
|
if _is_defusing:
|
||||||
|
request_cancel_defuse()
|
||||||
|
|
||||||
|
# Update prompt if changed
|
||||||
|
if prompt_text != _current_prompt or show_prompt != _prompt_visible:
|
||||||
|
_current_prompt = prompt_text
|
||||||
|
_prompt_visible = show_prompt
|
||||||
|
prompt_changed.emit(prompt_text, show_prompt)
|
||||||
|
|
||||||
|
func _emit_status_updates() -> void:
|
||||||
|
# Emit bomb status updates (rate-limited is handled by engine)
|
||||||
|
bomb_status_updated.emit(_bomb_planted, _bomb_timer, _is_defusing, _defuse_progress)
|
||||||
|
|
||||||
|
# Emit direction indicator if bomb is planted
|
||||||
|
if _bomb_planted and _character_controller != null:
|
||||||
|
var player_pos: Vector3 = _character_controller.global_position
|
||||||
|
var direction: Vector3 = _bomb_position - player_pos
|
||||||
|
var distance: float = direction.length()
|
||||||
|
if distance > 0.01:
|
||||||
|
var bearing: float = atan2(direction.x, -direction.z) # Relative to forward (Z)
|
||||||
|
bomb_direction_updated.emit(rad_to_deg(bearing), distance)
|
||||||
|
else:
|
||||||
|
bomb_direction_updated.emit(0.0, 0.0)
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Internal — Helpers
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
## Get the local player's team (from TeamManager singleton if available).
|
||||||
|
func _get_local_player_team() -> int:
|
||||||
|
var team_manager: TeamManager = get_node_or_null("/root/TeamManager")
|
||||||
|
if team_manager:
|
||||||
|
var peer_id: int = multiplayer.get_unique_id() if multiplayer.has_method(&\"get_unique_id\") else -1
|
||||||
|
if peer_id >= 0:
|
||||||
|
return team_manager.get_player_team(peer_id)
|
||||||
|
return -1
|
||||||
|
|
||||||
|
## Check if the current round is in LIVE phase.
|
||||||
|
func _is_round_live() -> bool:
|
||||||
|
var round_manager: RoundManager = get_node_or_null("/root/RoundManager")
|
||||||
|
if round_manager:
|
||||||
|
return round_manager.get_phase() == RoundManager.RoundPhase.LIVE
|
||||||
|
return false
|
||||||
|
|
||||||
|
## Get the multiplayer API (stub for compatibility).
|
||||||
|
func get_multiplayer() -> MultiplayerAPI:
|
||||||
|
if multiplayer and multiplayer.has_method(&\"get_unique_id\"):
|
||||||
|
return multiplayer
|
||||||
|
return null
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://dtvf72mhgdat7
|
||||||
@@ -0,0 +1,445 @@
|
|||||||
|
## BuyMenu — Client-side buy menu UI for weapon and equipment purchases.
|
||||||
|
##
|
||||||
|
## Displays a grid of purchasable weapons with name, cost, and key stats.
|
||||||
|
## Highlights weapons the player can afford, shows current money at the top,
|
||||||
|
## and supports both keyboard (numeric keys) and mouse-click selection.
|
||||||
|
##
|
||||||
|
## Opens during the PREP (buy) phase when the player is inside a buy zone.
|
||||||
|
## Automatically closes when the buy phase ends or the player leaves the zone.
|
||||||
|
##
|
||||||
|
## Usage (add as child of the player's UI root or HUD):
|
||||||
|
## var buy_menu = preload("res://client/characters/weapon/buy_menu.gd").new()
|
||||||
|
## add_child(buy_menu)
|
||||||
|
##
|
||||||
|
## # Show it
|
||||||
|
## buy_menu.open()
|
||||||
|
## buy_menu.populate(affordable_weapons_list, current_money)
|
||||||
|
##
|
||||||
|
## Signals:
|
||||||
|
## buy_menu_opened()
|
||||||
|
## buy_menu_closed()
|
||||||
|
## purchase_completed(weapon_id)
|
||||||
|
## purchase_failed(reason: String)
|
||||||
|
##
|
||||||
|
class_name BuyMenu
|
||||||
|
extends Control
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Signals
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
## Emitted when the buy menu opens.
|
||||||
|
signal buy_menu_opened()
|
||||||
|
|
||||||
|
## Emitted when the buy menu closes.
|
||||||
|
signal buy_menu_closed()
|
||||||
|
|
||||||
|
## Emitted when a purchase is confirmed by the server.
|
||||||
|
signal purchase_completed(weapon_id: String)
|
||||||
|
|
||||||
|
## Emitted when a purchase is denied by the server.
|
||||||
|
signal purchase_failed(reason: String)
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Exports — Layout
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
## Background panel colour.
|
||||||
|
@export var panel_color: Color = Color(0.1, 0.1, 0.15, 0.92)
|
||||||
|
|
||||||
|
## Accent colour for headers and affordable items.
|
||||||
|
@export var accent_color: Color = Color(0.2, 0.7, 0.3, 1.0)
|
||||||
|
|
||||||
|
## Colour for items the player cannot afford.
|
||||||
|
@export var unaffordable_color: Color = Color(0.5, 0.5, 0.5, 1.0)
|
||||||
|
|
||||||
|
## Text colour.
|
||||||
|
@export var text_color: Color = Color(0.95, 0.95, 0.95, 1.0)
|
||||||
|
|
||||||
|
## Key binding for opening the buy menu (default: B).
|
||||||
|
@export var open_key: Key = KEY_B
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Internal state
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
## Reference to the BuyMenuHandler on the server (for sending RPCs).
|
||||||
|
## Injected by the UI manager or found at runtime.
|
||||||
|
var buy_menu_handler_path: NodePath = NodePath()
|
||||||
|
|
||||||
|
var _is_open: bool = false
|
||||||
|
var _weapon_buttons: Array[Button] = []
|
||||||
|
var _populated: bool = false
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# UI Nodes (built in _build_ui)
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
var _panel: Panel = null
|
||||||
|
var _money_label: Label = null
|
||||||
|
var _title_label: Label = null
|
||||||
|
var _weapon_container: Container = null
|
||||||
|
var _close_button: Button = null
|
||||||
|
var _status_label: Label = null
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Lifecycle
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
_build_ui()
|
||||||
|
visible = false
|
||||||
|
|
||||||
|
# Listen for server purchase confirmations / denials
|
||||||
|
# The BuyMenuHandler sends RPCs that land on this node.
|
||||||
|
# We connect to them via the multiplayer API — they're named to match
|
||||||
|
# the RPC names defined in BuyMenuHandler.
|
||||||
|
|
||||||
|
# Connect input for toggle key
|
||||||
|
set_process_input(true)
|
||||||
|
|
||||||
|
func _input(event: InputEvent) -> void:
|
||||||
|
if event.is_action_pressed("buy_menu") or (
|
||||||
|
event is InputEventKey and
|
||||||
|
event.keycode == open_key and
|
||||||
|
event.pressed and
|
||||||
|
not event.echo
|
||||||
|
):
|
||||||
|
if _is_open:
|
||||||
|
close()
|
||||||
|
else:
|
||||||
|
open()
|
||||||
|
accept_event()
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# UI Construction
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
func _build_ui() -> void:
|
||||||
|
# Main panel — centred, sized to fit content
|
||||||
|
_panel = Panel.new()
|
||||||
|
_panel.anchor_left = 0.15
|
||||||
|
_panel.anchor_right = 0.85
|
||||||
|
_panel.anchor_top = 0.1
|
||||||
|
_panel.anchor_bottom = 0.9
|
||||||
|
_panel.mouse_filter = Control.MOUSE_FILTER_PASS
|
||||||
|
add_child(_panel)
|
||||||
|
|
||||||
|
# Panel background style
|
||||||
|
var style := StyleBoxFlat.new()
|
||||||
|
style.bg_color = panel_color
|
||||||
|
style.corner_radius_top_left = 8
|
||||||
|
style.corner_radius_top_right = 8
|
||||||
|
style.corner_radius_bottom_left = 8
|
||||||
|
style.corner_radius_bottom_right = 8
|
||||||
|
_panel.add_theme_stylebox_override("panel", style)
|
||||||
|
|
||||||
|
# Vertical layout inside the panel
|
||||||
|
var vbox := VBoxContainer.new()
|
||||||
|
vbox.anchor_left = 0.0
|
||||||
|
vbox.anchor_right = 1.0
|
||||||
|
vbox.anchor_top = 0.0
|
||||||
|
vbox.anchor_bottom = 1.0
|
||||||
|
vbox.add_theme_constant_override("separation", 12)
|
||||||
|
_panel.add_child(vbox)
|
||||||
|
|
||||||
|
# ── Title ──
|
||||||
|
_title_label = Label.new()
|
||||||
|
_title_label.text = "BUY MENU"
|
||||||
|
_title_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||||
|
_title_label.add_theme_font_size_override("font_size", 24)
|
||||||
|
_title_label.add_theme_color_override("font_color", accent_color)
|
||||||
|
vbox.add_child(_title_label)
|
||||||
|
|
||||||
|
# ── Money display ──
|
||||||
|
_money_label = Label.new()
|
||||||
|
_money_label.text = "$0"
|
||||||
|
_money_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||||
|
_money_label.add_theme_font_size_override("font_size", 20)
|
||||||
|
_money_label.add_theme_color_override("font_color", text_color)
|
||||||
|
vbox.add_child(_money_label)
|
||||||
|
|
||||||
|
# ── Weapon grid ──
|
||||||
|
_weapon_container = GridContainer.new()
|
||||||
|
_weapon_container.columns = 2
|
||||||
|
_weapon_container.add_theme_constant_override("h_separation", 16)
|
||||||
|
_weapon_container.add_theme_constant_override("v_separation", 8)
|
||||||
|
_weapon_container.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||||
|
_weapon_container.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||||
|
vbox.add_child(_weapon_container)
|
||||||
|
|
||||||
|
# ── Status / feedback line ──
|
||||||
|
_status_label = Label.new()
|
||||||
|
_status_label.text = ""
|
||||||
|
_status_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||||
|
_status_label.add_theme_color_override("font_color", Color(1.0, 0.8, 0.2, 1.0))
|
||||||
|
_status_label.add_theme_font_size_override("font_size", 14)
|
||||||
|
vbox.add_child(_status_label)
|
||||||
|
|
||||||
|
# ── Close hint ──
|
||||||
|
var close_hint := Label.new()
|
||||||
|
close_hint.text = "Press B or ESC to close | Click or press 1-4 to buy"
|
||||||
|
close_hint.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||||
|
close_hint.add_theme_font_size_override("font_size", 11)
|
||||||
|
close_hint.add_theme_color_override("font_color", Color(0.6, 0.6, 0.6, 1.0))
|
||||||
|
vbox.add_child(close_hint)
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Public API
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
## Open and populate the buy menu.
|
||||||
|
func open() -> void:
|
||||||
|
if _is_open:
|
||||||
|
return
|
||||||
|
|
||||||
|
_is_open = true
|
||||||
|
visible = true
|
||||||
|
_populated = false
|
||||||
|
_clear_weapons()
|
||||||
|
_status_label.text = ""
|
||||||
|
|
||||||
|
# Request affordable weapons from the server via an RPC call
|
||||||
|
# (The server pushes the data back via RPC response.)
|
||||||
|
_request_menu_data()
|
||||||
|
|
||||||
|
buy_menu_opened.emit()
|
||||||
|
|
||||||
|
## Close the buy menu.
|
||||||
|
func close() -> void:
|
||||||
|
if not _is_open:
|
||||||
|
return
|
||||||
|
_is_open = false
|
||||||
|
visible = false
|
||||||
|
buy_menu_closed.emit()
|
||||||
|
|
||||||
|
## Returns true if the menu is currently open.
|
||||||
|
func is_open() -> bool:
|
||||||
|
return _is_open
|
||||||
|
|
||||||
|
## Update the displayed money amount.
|
||||||
|
func set_money(amount: int) -> void:
|
||||||
|
_money_label.text = "$%d" % amount
|
||||||
|
|
||||||
|
## Populate the weapon grid with purchasable items.
|
||||||
|
## `weapons` is an Array[Dictionary] with keys:
|
||||||
|
## weapon_id, display_name, cost, damage, fire_rate, mag_size
|
||||||
|
## `current_money` is the player's balance.
|
||||||
|
func populate(weapons: Array[Dictionary], current_money: int) -> void:
|
||||||
|
_clear_weapons()
|
||||||
|
_populated = false
|
||||||
|
set_money(current_money)
|
||||||
|
|
||||||
|
var index: int = 1
|
||||||
|
for w in weapons:
|
||||||
|
var affordable: bool = (current_money >= w.get("cost", 0))
|
||||||
|
_add_weapon_button(index, w, affordable)
|
||||||
|
index += 1
|
||||||
|
|
||||||
|
_populated = true
|
||||||
|
|
||||||
|
## Show a temporary status message in the menu.
|
||||||
|
func show_status(message: String, duration: float = 3.0) -> void:
|
||||||
|
_status_label.text = message
|
||||||
|
if duration > 0:
|
||||||
|
get_tree().create_timer(duration).timeout.connect(func():
|
||||||
|
if is_instance_valid(_status_label) and _status_label.text == message:
|
||||||
|
_status_label.text = ""
|
||||||
|
)
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Internal: weapon button creation
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
func _add_weapon_button(index: int, data: Dictionary, affordable: bool) -> void:
|
||||||
|
var weapon_id: String = data.get("weapon_id", "")
|
||||||
|
var display_name: String = data.get("display_name", weapon_id)
|
||||||
|
var cost: int = data.get("cost", 0)
|
||||||
|
var damage: float = data.get("damage", 0.0)
|
||||||
|
var fire_rate: float = data.get("fire_rate", 0.0)
|
||||||
|
var mag_size: int = data.get("mag_size", 0)
|
||||||
|
|
||||||
|
# Build the weapon card as a styled Button
|
||||||
|
var btn := Button.new()
|
||||||
|
btn.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||||
|
btn.size_flags_vertical = Control.SIZE_SHRINK_CENTER
|
||||||
|
btn.custom_minimum_size = Vector2(240, 80)
|
||||||
|
|
||||||
|
# Text: name + cost on first line, stats on second
|
||||||
|
var stats_line: String = "%.0f dmg | %.1f rps | %d rds" % [damage, fire_rate, mag_size]
|
||||||
|
btn.text = "[%d] %s — $%d\n%s" % [index, display_name, cost, stats_line]
|
||||||
|
btn.flat = false
|
||||||
|
btn.tooltip_text = "%s — $%d\nDamage: %.0f\nFire Rate: %.1f Hz\nMagazine: %d rounds" % [
|
||||||
|
display_name, cost, damage, fire_rate, mag_size
|
||||||
|
]
|
||||||
|
|
||||||
|
# Style
|
||||||
|
var fg_color: Color = accent_color if affordable else unaffordable_color
|
||||||
|
btn.add_theme_color_override("font_color", fg_color)
|
||||||
|
btn.add_theme_color_override("font_hover_color", text_color)
|
||||||
|
btn.add_theme_color_override("font_pressed_color", Color.WHITE)
|
||||||
|
btn.add_theme_font_size_override("font_size", 14)
|
||||||
|
|
||||||
|
if not affordable:
|
||||||
|
btn.disabled = true
|
||||||
|
|
||||||
|
btn.pressed.connect(_on_weapon_button_pressed.bind(weapon_id, cost, btn))
|
||||||
|
_weapon_container.add_child(btn)
|
||||||
|
_weapon_buttons.append(btn)
|
||||||
|
|
||||||
|
func _clear_weapons() -> void:
|
||||||
|
for child in _weapon_buttons:
|
||||||
|
if is_instance_valid(child):
|
||||||
|
child.queue_free()
|
||||||
|
_weapon_buttons.clear()
|
||||||
|
_populated = false
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Internal: purchase flow
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
func _on_weapon_button_pressed(weapon_id: String, cost: int, _button: Button) -> void:
|
||||||
|
_request_purchase(weapon_id)
|
||||||
|
|
||||||
|
## Send a purchase request RPC to the server.
|
||||||
|
func _request_purchase(weapon_id: String) -> void:
|
||||||
|
_status_label.text = "Purchasing %s..." % weapon_id
|
||||||
|
|
||||||
|
# Find the BuyMenuHandler and call its buy_request RPC.
|
||||||
|
# The handler is typically a child of GameServer.
|
||||||
|
if multiplayer.is_server():
|
||||||
|
# Listen server / standalone — call directly
|
||||||
|
_call_buy_handler(weapon_id)
|
||||||
|
else:
|
||||||
|
# Dedicated client — send RPC
|
||||||
|
_call_buy_handler_rpc(weapon_id)
|
||||||
|
|
||||||
|
func _call_buy_handler(_weapon_id: String) -> void:
|
||||||
|
# On a listen server, the handler is local
|
||||||
|
var handler: BuyMenuHandler = _find_buy_handler()
|
||||||
|
if handler:
|
||||||
|
handler.buy_request.rpc(_weapon_id)
|
||||||
|
|
||||||
|
func _call_buy_handler_rpc(weapon_id: String) -> void:
|
||||||
|
# Find the handler path and send the RPC
|
||||||
|
var handler_path: NodePath = buy_menu_handler_path
|
||||||
|
if handler_path.is_empty():
|
||||||
|
# Try to find it dynamically
|
||||||
|
handler_path = "/root/GameServer/BuyMenuHandler"
|
||||||
|
var node: Node = get_node_or_null(handler_path) if not handler_path.is_empty() else null
|
||||||
|
if node and node.has_method(&"buy_request"):
|
||||||
|
node.buy_request.rpc(weapon_id)
|
||||||
|
else:
|
||||||
|
# Fallback: call directly on the handler node path
|
||||||
|
rpc_id(1, "_remote_buy_request", weapon_id)
|
||||||
|
|
||||||
|
## Fallback: send buy request to server's handler.
|
||||||
|
@rpc("any_peer", "call_remote", "reliable")
|
||||||
|
func _remote_buy_request(weapon_id: String) -> void:
|
||||||
|
if not multiplayer.is_server():
|
||||||
|
return
|
||||||
|
var handler: BuyMenuHandler = _find_buy_handler()
|
||||||
|
if handler:
|
||||||
|
var sender: int = multiplayer.get_remote_sender_id()
|
||||||
|
handler.call_deferred("_process_buy_request", sender, weapon_id)
|
||||||
|
|
||||||
|
func _find_buy_handler() -> BuyMenuHandler:
|
||||||
|
# Try common locations
|
||||||
|
var game_server: Node = get_node_or_null("/root/GameServer")
|
||||||
|
if game_server:
|
||||||
|
for child in game_server.get_children():
|
||||||
|
if child is BuyMenuHandler:
|
||||||
|
return child
|
||||||
|
return null
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# RPC handlers — called by BuyMenuHandler (server → client)
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
## Called by the server when a purchase succeeds.
|
||||||
|
@rpc("authority", "call_remote", "reliable")
|
||||||
|
func _on_buy_confirmed(weapon_id: String, cost: int) -> void:
|
||||||
|
show_status("Purchased %s for $%d" % [weapon_id, cost], 2.0)
|
||||||
|
purchase_completed.emit(weapon_id)
|
||||||
|
# Close after a brief delay so the player sees the confirmation
|
||||||
|
get_tree().create_timer(0.6).timeout.connect(close)
|
||||||
|
|
||||||
|
## Called by the server when a purchase is denied.
|
||||||
|
@rpc("authority", "call_remote", "reliable")
|
||||||
|
func _on_buy_denied(reason: String) -> void:
|
||||||
|
show_status("Purchase failed: %s" % reason, 3.0)
|
||||||
|
purchase_failed.emit(reason)
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Request affordable weapon data from the server
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
func _request_menu_data() -> void:
|
||||||
|
# For now, the client populates from the weapon definitions directly,
|
||||||
|
# filtering by what the server says is affordable.
|
||||||
|
# In a more advanced version, the server sends the curated list.
|
||||||
|
#
|
||||||
|
# Since we don't know the player's money on the client, we send an
|
||||||
|
# RPC to the server to get the affordable list. But for simplicity,
|
||||||
|
# we populate all weapons and let the server deny if unaffordable.
|
||||||
|
#
|
||||||
|
# The server pushes the affordable list back via get_affordable_weapons().
|
||||||
|
# For now, just show all weapons — the server will reject unaffordable ones.
|
||||||
|
|
||||||
|
# Try to fetch from server
|
||||||
|
if multiplayer.is_server():
|
||||||
|
_populate_from_local(player_id())
|
||||||
|
else:
|
||||||
|
_request_affordable_weapons.rpc_id(1)
|
||||||
|
|
||||||
|
## Get the player's peer ID.
|
||||||
|
func player_id() -> int:
|
||||||
|
return multiplayer.get_unique_id()
|
||||||
|
|
||||||
|
## Client → Server: request affordable weapon list.
|
||||||
|
@rpc("any_peer", "call_remote", "reliable")
|
||||||
|
func _request_affordable_weapons() -> void:
|
||||||
|
if not multiplayer.is_server():
|
||||||
|
return
|
||||||
|
var sender: int = multiplayer.get_remote_sender_id()
|
||||||
|
var handler: BuyMenuHandler = _find_buy_handler()
|
||||||
|
if handler:
|
||||||
|
var weapons: Array[Dictionary] = handler.get_affordable_weapons(sender)
|
||||||
|
var money: int = handler.get_player_money(sender)
|
||||||
|
_send_menu_data.rpc_id(sender, weapons, money)
|
||||||
|
|
||||||
|
## Server → Client: send affordable weapon list and money.
|
||||||
|
@rpc("authority", "call_remote", "reliable")
|
||||||
|
func _send_menu_data(weapons: Array[Dictionary], current_money: int) -> void:
|
||||||
|
populate(weapons, current_money)
|
||||||
|
|
||||||
|
func _populate_from_local(pid: int) -> void:
|
||||||
|
var handler: BuyMenuHandler = _find_buy_handler()
|
||||||
|
if handler:
|
||||||
|
var weapons: Array[Dictionary] = handler.get_affordable_weapons(pid)
|
||||||
|
var money: int = handler.get_player_money(pid)
|
||||||
|
populate(weapons, money)
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Input helpers
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
func _unhandled_key_input(event: InputEventKey) -> void:
|
||||||
|
if not _is_open or not _populated:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Numeric keys 1-4 to buy
|
||||||
|
var key: Key = event.keycode
|
||||||
|
var index: int = -1
|
||||||
|
match key:
|
||||||
|
KEY_1, KEY_KP_1: index = 0
|
||||||
|
KEY_2, KEY_KP_2: index = 1
|
||||||
|
KEY_3, KEY_KP_3: index = 2
|
||||||
|
KEY_4, KEY_KP_4: index = 3
|
||||||
|
|
||||||
|
if index >= 0 and index < _weapon_buttons.size():
|
||||||
|
var btn: Button = _weapon_buttons[index]
|
||||||
|
if btn and not btn.disabled and event.pressed:
|
||||||
|
btn.emit_signal("pressed")
|
||||||
|
accept_event()
|
||||||
|
|
||||||
|
# ESC to close
|
||||||
|
if event.keycode == KEY_ESCAPE and event.pressed:
|
||||||
|
close()
|
||||||
|
accept_event()
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://cdsyn134gsca8
|
||||||
@@ -0,0 +1,348 @@
|
|||||||
|
## WeaponManager — hitscan weapon system for tactical FPS.
|
||||||
|
##
|
||||||
|
## Manages a single hitscan weapon: fire rate limiting, ammo, reload.
|
||||||
|
## Communicates with SimulationServer for server-authoritative hit detection.
|
||||||
|
##
|
||||||
|
## Architecture:
|
||||||
|
## - Client-side: fire rate limiting, muzzle VFX, hit marker feedback
|
||||||
|
## - Server-side (via SimulationServer): hit detection, damage, lag compensation
|
||||||
|
## - Both sides: ammo tracking (server-authoritative, client-predicted)
|
||||||
|
##
|
||||||
|
## Usage (attach as child of FPSCharacterController):
|
||||||
|
##
|
||||||
|
## FPSCharacterController
|
||||||
|
## ├── WeaponManager — fire rate, ammo, VFX
|
||||||
|
## │ ├── MuzzleFlash — instantiated VFX
|
||||||
|
## │ └── HitMarker — instantiated VFX
|
||||||
|
## └── FpsCamera
|
||||||
|
##
|
||||||
|
class_name WeaponManager
|
||||||
|
extends Node
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Signals
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
## Emitted when the weapon fires (for visual feedback).
|
||||||
|
signal weapon_fired(origin: Vector3, direction: Vector3)
|
||||||
|
|
||||||
|
## Emitted when this weapon hits an entity.
|
||||||
|
signal hit_marked(hit_pos: Vector3, damage: float, killed: bool)
|
||||||
|
|
||||||
|
## Emitted when ammo changes.
|
||||||
|
signal ammo_changed(current: int, max: int)
|
||||||
|
|
||||||
|
## Emitted when player is killed.
|
||||||
|
signal player_killed()
|
||||||
|
|
||||||
|
## Emitted when the player switches weapons (for animation/UI).
|
||||||
|
signal weapon_switched(index: int, weapon_id: String)
|
||||||
|
|
||||||
|
## Emitted when the current weapon fires (for animation/visual sync).
|
||||||
|
## Connected by animation players or VFX systems on the weapon model.
|
||||||
|
signal fire_animation_triggered()
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Exports — Assault Rifle Config
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
## Maximum ammo capacity.
|
||||||
|
@export var max_ammo: int = 30
|
||||||
|
|
||||||
|
## Starting ammo (including one magazine).
|
||||||
|
@export var start_ammo: int = 90
|
||||||
|
|
||||||
|
## Time between shots (seconds). 10 Hz = 0.1s between shots.
|
||||||
|
@export var fire_rate: float = 0.1
|
||||||
|
|
||||||
|
## Reload time in seconds.
|
||||||
|
@export var reload_time: float = 2.0
|
||||||
|
|
||||||
|
## Spread increases while firing (degrees).
|
||||||
|
@export var spread_per_shot: float = 0.5
|
||||||
|
|
||||||
|
## Max spread when firing continuously (degrees).
|
||||||
|
@export var max_spread: float = 4.0
|
||||||
|
|
||||||
|
## Spread recovery per second (degrees/s).
|
||||||
|
@export var spread_recovery: float = 8.0
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# State
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
var current_ammo: int = 30
|
||||||
|
var reserve_ammo: int = 90
|
||||||
|
var is_reloading: bool = false
|
||||||
|
var _last_shot_time: float = 0.0
|
||||||
|
var _current_spread: float = 0.0
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Multi-weapon inventory state
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
## Array of weapon IDs the player carries (the inventory).
|
||||||
|
var _weapon_inventory: Array[String] = []
|
||||||
|
|
||||||
|
## Index into _weapon_inventory for the currently equipped weapon.
|
||||||
|
var _current_weapon_index: int = -1
|
||||||
|
|
||||||
|
## Per-weapon persistent state saved when switching away, restored on switch-back.
|
||||||
|
## weapon_id -> { ammo, reserve, is_reloading, last_shot_time, current_spread }
|
||||||
|
var _weapon_states: Dictionary = {}
|
||||||
|
|
||||||
|
## Reference to the parent FPSCharacterController (set in _ready).
|
||||||
|
var _controller: FPSCharacterController = null
|
||||||
|
|
||||||
|
## Reference to SimulationServer (if available).
|
||||||
|
var _server: Object = null
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Lifecycle
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
_controller = get_parent() as FPSCharacterController
|
||||||
|
if _controller == null:
|
||||||
|
push_warning("WeaponManager: Parent is not FPSCharacterController. Disabled.")
|
||||||
|
set_process(false)
|
||||||
|
return
|
||||||
|
|
||||||
|
# Find SimulationServer singleton
|
||||||
|
if Engine.has_singleton("SimulationServer"):
|
||||||
|
_server = Engine.get_singleton("SimulationServer")
|
||||||
|
elif Engine.get_main_loop() and Engine.get_main_loop().root:
|
||||||
|
# Try finding it in the scene tree
|
||||||
|
var game_server = Engine.get_main_loop().root.find_child("GameServer", true, false)
|
||||||
|
if game_server and game_server.has_method(&"get_simulation_server"):
|
||||||
|
_server = game_server.get_simulation_server()
|
||||||
|
|
||||||
|
# Initialize ammo
|
||||||
|
current_ammo = max_ammo
|
||||||
|
reserve_ammo = start_ammo
|
||||||
|
|
||||||
|
# Signal that ammo changed
|
||||||
|
ammo_changed.emit(current_ammo, max_ammo)
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Main loop — called from FPSCharacterController._physics_process per tick
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
## Try to fire the weapon. Returns true if a shot was fired.
|
||||||
|
## Called by the controller when shoot input is detected.
|
||||||
|
func try_fire(time: float) -> bool:
|
||||||
|
# Check fire rate
|
||||||
|
if time - _last_shot_time < fire_rate:
|
||||||
|
return false
|
||||||
|
|
||||||
|
# Check ammo
|
||||||
|
if current_ammo <= 0:
|
||||||
|
# Auto-reload on empty — or play empty-click sound
|
||||||
|
if not is_reloading:
|
||||||
|
start_reload()
|
||||||
|
return false
|
||||||
|
|
||||||
|
# Check reloading
|
||||||
|
if is_reloading:
|
||||||
|
return false
|
||||||
|
|
||||||
|
# Deduct ammo
|
||||||
|
current_ammo -= 1
|
||||||
|
_last_shot_time = time
|
||||||
|
|
||||||
|
# Increase spread
|
||||||
|
_current_spread = min(_current_spread + spread_per_shot, max_spread)
|
||||||
|
|
||||||
|
# Persist state back to per-weapon dict
|
||||||
|
_save_current_weapon_state()
|
||||||
|
|
||||||
|
# Emit fire signal (for visual/hit marker)
|
||||||
|
# Direction comes from the controller's look direction
|
||||||
|
if _controller:
|
||||||
|
var origin: Vector3 = _controller.global_position
|
||||||
|
origin.y += _controller.eye_height_stand
|
||||||
|
var direction: Vector3 = _controller.get_look_direction()
|
||||||
|
weapon_fired.emit(origin, direction)
|
||||||
|
|
||||||
|
ammo_changed.emit(current_ammo, max_ammo)
|
||||||
|
fire_animation_triggered.emit()
|
||||||
|
return true
|
||||||
|
|
||||||
|
## Called every frame to recover spread and handle spread animation.
|
||||||
|
func _process(delta: float) -> void:
|
||||||
|
# Recover spread
|
||||||
|
if _current_spread > 0.0:
|
||||||
|
_current_spread = max(0.0, _current_spread - spread_recovery * delta)
|
||||||
|
|
||||||
|
## Start reloading.
|
||||||
|
func start_reload() -> void:
|
||||||
|
if is_reloading or current_ammo >= max_ammo or reserve_ammo <= 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
is_reloading = true
|
||||||
|
await get_tree().create_timer(reload_time).timeout
|
||||||
|
|
||||||
|
# Reload logic
|
||||||
|
var needed: int = max_ammo - current_ammo
|
||||||
|
var from_reserve: int = min(needed, reserve_ammo)
|
||||||
|
current_ammo += from_reserve
|
||||||
|
reserve_ammo -= from_reserve
|
||||||
|
is_reloading = false
|
||||||
|
|
||||||
|
ammo_changed.emit(current_ammo, max_ammo)
|
||||||
|
_save_current_weapon_state()
|
||||||
|
|
||||||
|
## Called when a hit is confirmed by the server.
|
||||||
|
func on_hit_confirmed(hit_pos: Vector3, damage: float, killed: bool) -> void:
|
||||||
|
hit_marked.emit(hit_pos, damage, killed)
|
||||||
|
if killed:
|
||||||
|
player_killed.emit()
|
||||||
|
|
||||||
|
## Get current spread (degrees).
|
||||||
|
func get_current_spread() -> float:
|
||||||
|
return _current_spread
|
||||||
|
|
||||||
|
## Get the current weapon fire direction including spread cone.
|
||||||
|
func get_spread_direction(base_direction: Vector3) -> Vector3:
|
||||||
|
if _current_spread <= 0.001:
|
||||||
|
return base_direction
|
||||||
|
|
||||||
|
var spread_rad: float = deg_to_rad(_current_spread)
|
||||||
|
var theta: float = randf() * TAU
|
||||||
|
var phi: float = randf() * spread_rad
|
||||||
|
|
||||||
|
# Create a random perpendicular vector
|
||||||
|
var up := Vector3.UP
|
||||||
|
if abs(base_direction.dot(up)) > 0.99:
|
||||||
|
up = Vector3.RIGHT
|
||||||
|
var right := base_direction.cross(up).normalized()
|
||||||
|
up = right.cross(base_direction).normalized()
|
||||||
|
|
||||||
|
var offset := right * sin(theta) * sin(phi) + up * cos(theta) * sin(phi)
|
||||||
|
return (base_direction + offset).normalized()
|
||||||
|
|
||||||
|
## Reset weapon state (for respawn).
|
||||||
|
func reset() -> void:
|
||||||
|
# Re-initialise all weapon states in inventory
|
||||||
|
for wid in _weapon_inventory:
|
||||||
|
_initialize_weapon_state(wid)
|
||||||
|
# Apply current weapon (or use defaults if no inventory)
|
||||||
|
if _current_weapon_index >= 0 and _current_weapon_index < _weapon_inventory.size():
|
||||||
|
_apply_current_weapon()
|
||||||
|
else:
|
||||||
|
current_ammo = max_ammo
|
||||||
|
reserve_ammo = start_ammo
|
||||||
|
is_reloading = false
|
||||||
|
_current_spread = 0.0
|
||||||
|
_last_shot_time = 0.0
|
||||||
|
ammo_changed.emit(current_ammo, max_ammo)
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Weapon inventory management
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
## Add a weapon to the player's inventory.
|
||||||
|
## If no weapon is currently equipped, this one is automatically selected.
|
||||||
|
func add_weapon(weapon_id: String) -> void:
|
||||||
|
if weapon_id in _weapon_inventory:
|
||||||
|
return
|
||||||
|
_weapon_inventory.append(weapon_id)
|
||||||
|
_initialize_weapon_state(weapon_id)
|
||||||
|
if _current_weapon_index < 0:
|
||||||
|
_current_weapon_index = _weapon_inventory.size() - 1
|
||||||
|
_apply_current_weapon()
|
||||||
|
|
||||||
|
## Switch to a weapon by its inventory index.
|
||||||
|
## Returns true if the switch was performed.
|
||||||
|
func switch_weapon(index: int) -> bool:
|
||||||
|
if index < 0 or index >= _weapon_inventory.size():
|
||||||
|
return false
|
||||||
|
if index == _current_weapon_index:
|
||||||
|
return false
|
||||||
|
_save_current_weapon_state()
|
||||||
|
_current_weapon_index = index
|
||||||
|
_apply_current_weapon()
|
||||||
|
weapon_switched.emit(index, _weapon_inventory[index])
|
||||||
|
return true
|
||||||
|
|
||||||
|
## Return the WeaponData for the currently equipped weapon, or null.
|
||||||
|
func current_weapon_data() -> WeaponData:
|
||||||
|
var wid := get_current_weapon_id()
|
||||||
|
if wid.is_empty():
|
||||||
|
return null
|
||||||
|
return WeaponDefinitions.get_weapon(wid)
|
||||||
|
|
||||||
|
## Return the current weapon's ID string, or empty string.
|
||||||
|
func get_current_weapon_id() -> String:
|
||||||
|
if _current_weapon_index >= 0 and _current_weapon_index < _weapon_inventory.size():
|
||||||
|
return _weapon_inventory[_current_weapon_index]
|
||||||
|
return ""
|
||||||
|
|
||||||
|
## Return the number of weapons in the inventory.
|
||||||
|
func get_weapon_count() -> int:
|
||||||
|
return _weapon_inventory.size()
|
||||||
|
|
||||||
|
## Return the list of weapon IDs in the inventory.
|
||||||
|
func get_inventory() -> Array[String]:
|
||||||
|
return _weapon_inventory.duplicate()
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Internal: per-weapon state management
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
## Initialise state dict for a weapon with default values.
|
||||||
|
func _initialize_weapon_state(weapon_id: String) -> void:
|
||||||
|
var data := WeaponDefinitions.get_weapon(weapon_id)
|
||||||
|
if data == null:
|
||||||
|
return
|
||||||
|
_weapon_states[weapon_id] = {
|
||||||
|
ammo = data.mag_size,
|
||||||
|
reserve = data.mag_size * 3,
|
||||||
|
is_reloading = false,
|
||||||
|
last_shot_time = 0.0,
|
||||||
|
current_spread = 0.0,
|
||||||
|
}
|
||||||
|
|
||||||
|
## Save the current weapon's runtime state back into _weapon_states.
|
||||||
|
func _save_current_weapon_state() -> void:
|
||||||
|
var wid := get_current_weapon_id()
|
||||||
|
if wid.is_empty() or not (wid in _weapon_states):
|
||||||
|
return
|
||||||
|
_weapon_states[wid] = {
|
||||||
|
ammo = current_ammo,
|
||||||
|
reserve = reserve_ammo,
|
||||||
|
is_reloading = is_reloading,
|
||||||
|
last_shot_time = _last_shot_time,
|
||||||
|
current_spread = _current_spread,
|
||||||
|
}
|
||||||
|
|
||||||
|
## Load the weapon at _current_weapon_index and apply its data + state
|
||||||
|
## to the live export properties and state variables.
|
||||||
|
func _apply_current_weapon() -> void:
|
||||||
|
var wid := get_current_weapon_id()
|
||||||
|
if wid.is_empty():
|
||||||
|
return
|
||||||
|
var data := WeaponDefinitions.get_weapon(wid)
|
||||||
|
if data == null:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Set export defaults from weapon data
|
||||||
|
max_ammo = data.mag_size
|
||||||
|
start_ammo = data.mag_size * 4 # 1 in mag + 3 reserve = 4x
|
||||||
|
fire_rate = 1.0 / max(data.fire_rate, 0.001)
|
||||||
|
reload_time = data.reload_time
|
||||||
|
spread_per_shot = data.spread_degrees * 0.1
|
||||||
|
max_spread = data.spread_degrees * 3.0
|
||||||
|
spread_recovery = data.spread_degrees * 8.0
|
||||||
|
|
||||||
|
# Restore per-weapon state
|
||||||
|
var st: Dictionary = _weapon_states.get(wid, {})
|
||||||
|
if st.is_empty():
|
||||||
|
_initialize_weapon_state(wid)
|
||||||
|
st = _weapon_states.get(wid, {})
|
||||||
|
current_ammo = st.get("ammo", data.mag_size)
|
||||||
|
reserve_ammo = st.get("reserve", data.mag_size * 3)
|
||||||
|
is_reloading = st.get("is_reloading", false)
|
||||||
|
_last_shot_time = st.get("last_shot_time", 0.0)
|
||||||
|
_current_spread = st.get("current_spread", 0.0)
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://dywlbha8xivx4
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://q8nutj781fyf
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://d0mbp6gs2mwlr
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://c0b8h1hq57lsu
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://pauclwpn265a
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://byjqslju7qnt6
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://jih7knhnl55a
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://dc8x14rs2jyu8
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://b8jj7n3bi6ljh
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://dbtpbhja3nk60
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://cwvi2ic1k6ubn
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://olpdh1gx2gca
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://bqau1kivb87fk
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://d0go24t1lsx2j
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://bas55o1773n21
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 174 B |
Binary file not shown.
|
After Width: | Height: | Size: 282 B |
@@ -0,0 +1,127 @@
|
|||||||
|
[gd_scene load_steps=11 format=4 uid="uid://br6g3dtbytwpu"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://deaf6cmuofa0" path="res://client/template/scripts/Weapon_State_Machine/PickUp Weapons/Weapon_Pick_Up.gd" id="1_mpf05"]
|
||||||
|
[ext_resource type="Script" uid="uid://bw4j1fbww4k8s" path="res://client/template/scripts/Weapon_State_Machine/WeaponSlot.gd" id="2_vl0jl"]
|
||||||
|
[ext_resource type="Resource" uid="uid://bwrs8ensewkgc" path="res://client/template/scripts/Weapon_State_Machine/Weapon_Resources/blasterL.tres" id="3_bkkd8"]
|
||||||
|
|
||||||
|
[sub_resource type="Resource" id="Resource_3vvaw"]
|
||||||
|
resource_local_to_scene = true
|
||||||
|
script = ExtResource("2_vl0jl")
|
||||||
|
weapon = ExtResource("3_bkkd8")
|
||||||
|
current_ammo = 30
|
||||||
|
reserve_ammo = 0
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_761wa"]
|
||||||
|
resource_name = "metal"
|
||||||
|
vertex_color_use_as_albedo = true
|
||||||
|
albedo_color = Color(0.454902, 0.431373, 0.403922, 1)
|
||||||
|
metallic = 1.0
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_757o3"]
|
||||||
|
resource_name = "darkMetal"
|
||||||
|
vertex_color_use_as_albedo = true
|
||||||
|
albedo_color = Color(0.454902, 0.431373, 0.403922, 1)
|
||||||
|
metallic = 1.0
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_0y2bu"]
|
||||||
|
resource_name = "yellow"
|
||||||
|
vertex_color_use_as_albedo = true
|
||||||
|
albedo_color = Color(0.533333, 0.984314, 0.976471, 1)
|
||||||
|
metallic = 1.0
|
||||||
|
emission_enabled = true
|
||||||
|
emission = Color(0.282353, 0.568627, 0.541176, 1)
|
||||||
|
emission_energy_multiplier = 9.4
|
||||||
|
|
||||||
|
[sub_resource type="ArrayMesh" id="ArrayMesh_bjg0s"]
|
||||||
|
_surfaces = [{
|
||||||
|
"aabb": AABB(-0.03, -0.12, -0.075, 0.06, 0.24, 0.15),
|
||||||
|
"format": 34359742465,
|
||||||
|
"index_count": 168,
|
||||||
|
"index_data": PackedByteArray("AgAAAAEAAQADAAIABgAEAAUABQAHAAYAAwABAAgACAAJAAMADAAKAAsACwANAAwADAAOAA8ADwAKAAwAEgAQABEAEQATABIAEgAJAAgACAAQABIAEQAAAAIAAgATABEACwAEAAYABgANAAsAFQAUABEAEQAWABUAEQAQABYAEAAIABYAAAARABQAFAAXAAAAFwABAAAAFwAYAAEAGAAIAAEAGAAWAAgAGgAZAAYABgAbABoABgAHABsABwAcABsABwAOABwADgAMABwADQAGABkAGQAdAA0AHQAMAA0AHQAcAAwAGQAaABQAFAAVABkAFgAYABwAHAAdABYAFQAWAB4AHgAZABUAHgAfABkAHwAgABkAIQAeABYAFgAdACEAHQAgACEAHQAZACAAGwAXABQAFAAaABsAHAAYABcAFwAbABwABwAFAA8ADwAOAAcA"),
|
||||||
|
"name": "metal",
|
||||||
|
"primitive": 3,
|
||||||
|
"uv_scale": Vector4(0, 0, 0, 0),
|
||||||
|
"vertex_count": 56,
|
||||||
|
"vertex_data": PackedByteArray("kML1vIaWnL3rUTg9kML1vOtRuL2wyJI8CtcjvIaWnL3rUTg9CtcjvOtRuL2wyJI8CtcjPIaWnL3rUTg9CtcjPOtRuL2wyJI8kML1PIaWnL3rUTg9kML1POtRuL2wyJI8kML1vOtRuL3rUTi9CtcjvOtRuL3rUTi9CtcjPArXoz3rUTi9CtcjPArXoz3rUTg9kML1PArXoz3rUTi9kML1PArXoz3rUTg9kML1POtRuL3rUTi9CtcjPOtRuL3rUTi9kML1vArXoz3rUTi9kML1vArXoz3rUTg9CtcjvArXoz3rUTi9CtcjvArXoz3rUTg9kML1vFyPwr2amZk9kML1vK1H4T2amZk9kML1vK1H4T2amZm9kML1vJDC9b3NzMw8kML1vJDC9b2amZm9kML1PK1H4T2amZk9kML1PFyPwr2amZk9kML1PJDC9b3NzMw8kML1PJDC9b2amZm9kML1PK1H4T2amZm9CtcjvK1H4T3rUTg9CtcjPK1H4T3rUTg9CtcjPK1H4T3rUTi9CtcjvK1H4T3rUTi93kEevKKU5j3rUTi93kEePKKU5j3rUTi9vOMNvB+F6z3rUTi9vOMNPB+F6z3rUTi9a7TnO/TC7z3rUTi9a7Tnu/TC7z3rUTi9CtejuyYE8z3rUTi9CtejOyYE8z3rUTi9oZ4pu+kP9T3rUTi9oZ4pO+kP9T3rUTi9AAAAAJDC9T3rUTi9a7Tnu/TC7z3rUTg9CtejuyYE8z3rUTg9vOMNPB+F6z3rUTg9a7TnO/TC7z3rUTg93kEePKKU5j3rUTg93kEevKKU5j3rUTg9vOMNvB+F6z3rUTg9CtejOyYE8z3rUTg9oZ4pO+kP9T3rUTg9oZ4pu+kP9T3rUTg9AAAAAJDC9T3rUTg9")
|
||||||
|
}, {
|
||||||
|
"aabb": AABB(-0.03, -0.12, -0.075, 0.06, 0.24, 0.15),
|
||||||
|
"format": 34359742465,
|
||||||
|
"index_count": 18,
|
||||||
|
"index_data": PackedByteArray("EgATAAIAAgADABIAAwAJABIABQAEAAsACwAKAAUACgAPAAUA"),
|
||||||
|
"name": "darkMetal",
|
||||||
|
"primitive": 3,
|
||||||
|
"uv_scale": Vector4(0, 0, 0, 0),
|
||||||
|
"vertex_count": 56,
|
||||||
|
"vertex_data": PackedByteArray("kML1vIaWnL3rUTg9kML1vOtRuL2wyJI8CtcjvIaWnL3rUTg9CtcjvOtRuL2wyJI8CtcjPIaWnL3rUTg9CtcjPOtRuL2wyJI8kML1PIaWnL3rUTg9kML1POtRuL2wyJI8kML1vOtRuL3rUTi9CtcjvOtRuL3rUTi9CtcjPArXoz3rUTi9CtcjPArXoz3rUTg9kML1PArXoz3rUTi9kML1PArXoz3rUTg9kML1POtRuL3rUTi9CtcjPOtRuL3rUTi9kML1vArXoz3rUTi9kML1vArXoz3rUTg9CtcjvArXoz3rUTi9CtcjvArXoz3rUTg9kML1vFyPwr2amZk9kML1vK1H4T2amZk9kML1vK1H4T2amZm9kML1vJDC9b3NzMw8kML1vJDC9b2amZm9kML1PK1H4T2amZk9kML1PFyPwr2amZk9kML1PJDC9b3NzMw8kML1PJDC9b2amZm9kML1PK1H4T2amZm9CtcjvK1H4T3rUTg9CtcjPK1H4T3rUTg9CtcjPK1H4T3rUTi9CtcjvK1H4T3rUTi93kEevKKU5j3rUTi93kEePKKU5j3rUTi9vOMNvB+F6z3rUTi9vOMNPB+F6z3rUTi9a7TnO/TC7z3rUTi9a7Tnu/TC7z3rUTi9CtejuyYE8z3rUTi9CtejOyYE8z3rUTi9oZ4pu+kP9T3rUTi9oZ4pO+kP9T3rUTi9AAAAAJDC9T3rUTi9a7Tnu/TC7z3rUTg9CtejuyYE8z3rUTg9vOMNPB+F6z3rUTg9a7TnO/TC7z3rUTg93kEePKKU5j3rUTg93kEevKKU5j3rUTg9vOMNvB+F6z3rUTg9CtejOyYE8z3rUTg9oZ4pO+kP9T3rUTg9oZ4pu+kP9T3rUTg9AAAAAJDC9T3rUTg9")
|
||||||
|
}, {
|
||||||
|
"aabb": AABB(-0.03, -0.12, -0.075, 0.06, 0.24, 0.15),
|
||||||
|
"format": 34359742465,
|
||||||
|
"index_count": 138,
|
||||||
|
"index_data": PackedByteArray("IgAhACAAIAAjACIAIwAkACIAIwAlACQAJQAmACQAJgAnACQAJgAoACcAJgApACgAKQAqACgAKQArACoAKwAsACoALgAtACcAJwAoAC4AJQAvADAAMAAmACUAMQAfAB4AHgAyADEAMgAvADEAMgAzAC8AMwAwAC8AMwAtADAALQA0ADAALQAuADQALgA1ADQALgA2ADUANgA3ADUAJwAtADMAMwAkACcAIgAyAB4AHgAhACIANQA3ACwALAArADUANAA1ACsAKwApADQAIwAxAC8ALwAlACMAIAAfADEAMQAjACAAMAA0ACkAKQAmADAAJAAzADIAMgAiACQANgAuACgAKAAqADYANwA2ACoAKgAsADcA"),
|
||||||
|
"name": "yellow",
|
||||||
|
"primitive": 3,
|
||||||
|
"uv_scale": Vector4(0, 0, 0, 0),
|
||||||
|
"vertex_count": 56,
|
||||||
|
"vertex_data": PackedByteArray("kML1vIaWnL3rUTg9kML1vOtRuL2wyJI8CtcjvIaWnL3rUTg9CtcjvOtRuL2wyJI8CtcjPIaWnL3rUTg9CtcjPOtRuL2wyJI8kML1PIaWnL3rUTg9kML1POtRuL2wyJI8kML1vOtRuL3rUTi9CtcjvOtRuL3rUTi9CtcjPArXoz3rUTi9CtcjPArXoz3rUTg9kML1PArXoz3rUTi9kML1PArXoz3rUTg9kML1POtRuL3rUTi9CtcjPOtRuL3rUTi9kML1vArXoz3rUTi9kML1vArXoz3rUTg9CtcjvArXoz3rUTi9CtcjvArXoz3rUTg9kML1vFyPwr2amZk9kML1vK1H4T2amZk9kML1vK1H4T2amZm9kML1vJDC9b3NzMw8kML1vJDC9b2amZm9kML1PK1H4T2amZk9kML1PFyPwr2amZk9kML1PJDC9b3NzMw8kML1PJDC9b2amZm9kML1PK1H4T2amZm9CtcjvK1H4T3rUTg9CtcjPK1H4T3rUTg9CtcjPK1H4T3rUTi9CtcjvK1H4T3rUTi93kEevKKU5j3rUTi93kEePKKU5j3rUTi9vOMNvB+F6z3rUTi9vOMNPB+F6z3rUTi9a7TnO/TC7z3rUTi9a7Tnu/TC7z3rUTi9CtejuyYE8z3rUTi9CtejOyYE8z3rUTi9oZ4pu+kP9T3rUTi9oZ4pO+kP9T3rUTi9AAAAAJDC9T3rUTi9a7Tnu/TC7z3rUTg9CtejuyYE8z3rUTg9vOMNPB+F6z3rUTg9a7TnO/TC7z3rUTg93kEePKKU5j3rUTg93kEevKKU5j3rUTg9vOMNvB+F6z3rUTg9CtejOyYE8z3rUTg9oZ4pO+kP9T3rUTg9oZ4pu+kP9T3rUTg9AAAAAJDC9T3rUTg9")
|
||||||
|
}]
|
||||||
|
blend_shape_mode = 0
|
||||||
|
|
||||||
|
[sub_resource type="ArrayMesh" id="ArrayMesh_wf2rx"]
|
||||||
|
resource_name = "clipA_Mesh clipA"
|
||||||
|
_surfaces = [{
|
||||||
|
"aabb": AABB(-0.03, -0.12, -0.075, 0.06, 0.24, 0.15),
|
||||||
|
"attribute_data": PackedByteArray("XS6XP0T3Qj9dLpc/dxH6PyaTyT5E90I/JpPJPncR+j8mk8m+RPdCPyaTyb53Efo/XS6Xv0T3Qj9dLpe/dxH6P10ul7+US9o/XS6XvxaLRb8mk8m+lEvaPyaTyb4Wi0W/JpPJvhaLRb8mk8m+xmIxQF0ul78Wi0W/XS6Xv8ZiMUBdLpc/xmKRQCaTyT7GYpFAXS6XPyaTCcAmk8k+JpMJwF0ulz8Wi0W/XS6XP8ZiMUAmk8k+FotFvyaTyT7GYjFAJpPJvsZikUBdLpe/xmKRQCaTyb4mkwnAXS6XvyaTCcBdLpc/hlOAQCaTyT6GU4BAXS6XPyaTCcAmk8k+JpMJwCaTyb6GU4BAXS6Xv4ZTgEAmk8m+JpMJwF0ul78mkwnA9Pk8QF6vl0CLxeI/JpMJwPT5PEBUKlXA9Pk8wFQqVcCLxeK/JpMJwIvF4r/GYpFAi8XiP4ZTgEDw93s/XS63QCmXND/GYpFA9Pk8wF0ut0D0+TzAVCpVwIvF4r+GU4BA9Pk8wF6vl0Dw93u/XS63QCmXNL/GYpFA9Pk8QF0ut0CLxeI/xmKRQIvF4j8mkwnAi8XivyaTCcD0+TxAVCpVwF0ulz9er5dAXS6Xv16vl0BdLpc/VCpVwF0ul79UKlXAXS6XP10ut0BdLpe/XS63QF0ulz9UKlXAXS6Xv1QqVcBdLpe/6PP5vyaTyb7GYjFAXS6Xv/T5fEBdLpc/9Pl8QCaTyT7GYjFAJpPJPhaLRb8mk8m+FotFv10ulz/o8/m/XS6Xv+3gDkBdLpe/QIgBPV0ulz/t4A5AXS6XP0CIAT1dLpc/6PP5v10ulz/4+/0/XS6Xv+jz+b9dLpe/+Pv9PyaTyT6US9o/JpPJPhaLRb9dLpc/lEvaP10ulz8Wi0W/i8XiPyaTCcCLxeI/hlOAQIvF4r8mkwnAKZc0P8ZikUCLxeK/xmKRQIvF4r+GU4BAi8XivyaTCcAplzS/xmKRQIvF4j8mkwnAi8XiP8ZikUAmk8k+VCpVwCaTyb5UKlXA0bTCPtCvW8DRtMK+0K9bwKORrj6Iw2HAo5GuvojDYcDwiI6+cvtmwPCIjj5y+2bAJpNJPor8asAmk0m+ivxqwIOv0D3ugG3Ag6/Qve6AbcDxsKoOulxuwIvF4j+g4Mq/i8Xiv6Dgyr+LxeI/agjYv4vF4r9qCNi/i8Xiv+mZGMCLxeK/zS0fwIvF4j/pmRjAi8XiP80tH8Amk8k+VCpVwCaTyb5UKlXA0bTCPtCvW8DRtMK+0K9bwKORrj6Iw2HAo5GuvojDYcDwiI4+cvtmwPCIjr5y+2bAJpNJPor8asAmk0m+ivxqwIOv0D3ugG3Ag6/Qve6AbcAJafYNulxuwIvF4j/NLR/Ai8XiP+mZGMCLxeK/zS0fwIvF4r/pmRjAi8XiP0AVVsCLxeI/XIFPwIvF4r9AFVbAi8Xiv1yBT8CLxeK/QEXEPovF4j9ARcQ+i8Xiv2Dk+D6LxeI/YOT4PovF4r/4azW/i8XiP/hrNb+LxeK/aBwbv4vF4j9oHBu/i8Xiv0/HPMCLxeK/MltDwIvF4j9PxzzAi8XiPzJbQ8CLxeK/XIFPwIvF4r9AFVbAi8XiP1yBT8CLxeI/QBVWwIvF4r9qCNi/i8XiP2oI2L+LxeK/oODKv4vF4j+g4Mq/i8XiPzJbQ8CLxeI/T8c8wIvF4r8yW0PAi8Xiv0/HPMCLxeI/aBwbv4vF4r9oHBu/i8XiP/hrNb+LxeK/+Gs1v4vF4j9g5Pg+i8Xiv2Dk+D6LxeI/QEXEPovF4r9ARcQ+"),
|
||||||
|
"format": 34359742487,
|
||||||
|
"index_count": 168,
|
||||||
|
"index_data": PackedByteArray("AgAAAAEAAQADAAIABgAEAAUABQAHAAYACgAIAAkACQALAAoADgAMAA0ADQAPAA4AEgAQABEAEQATABIAFgAUABUAFQAXABYAGgAYABkAGQAbABoAHgAcAB0AHQAfAB4AIgAgACEAIQAjACIAJgAkACUAJQAnACYAJQAoACcAKAApACcAKgAlACQAJAArACoAKwAsACoAKwAtACwALQApACwALQAnACkAMAAuAC8ALwAxADAALwAyADEAMgAzADEAMgA0ADMANAA1ADMANgAvAC4ALgA3ADYANwA1ADYANwAzADUAOgA4ADkAOQA7ADoAPgA8AD0APQA/AD4AQgBAAEEAQQBDAEIAQQBEAEMARABFAEMARgBBAEAAQABHAEYARwBFAEYARwBDAEUASgBIAEkASQBLAEoATgBMAE0ATQBPAE4AUgBQAFEAUQBTAFIA"),
|
||||||
|
"material": SubResource("StandardMaterial3D_761wa"),
|
||||||
|
"name": "metal",
|
||||||
|
"primitive": 3,
|
||||||
|
"uv_scale": Vector4(0, 0, 0, 0),
|
||||||
|
"vertex_count": 168,
|
||||||
|
"vertex_data": PackedByteArray("kML1vIaWnL3rUTg9kML1vOtRuL2wyJI8CtcjvIaWnL3rUTg9CtcjvOtRuL2wyJI8CtcjPIaWnL3rUTg9CtcjPOtRuL2wyJI8kML1PIaWnL3rUTg9kML1POtRuL2wyJI8kML1vOtRuL2wyJI8kML1vOtRuL3rUTi9CtcjvOtRuL2wyJI8CtcjvOtRuL3rUTi9CtcjPArXoz3rUTi9CtcjPArXoz3rUTg9kML1PArXoz3rUTi9kML1PArXoz3rUTg9kML1POtRuL3rUTi9CtcjPOtRuL3rUTi9kML1PArXoz3rUTi9CtcjPArXoz3rUTi9kML1vArXoz3rUTi9kML1vArXoz3rUTg9CtcjvArXoz3rUTi9CtcjvArXoz3rUTg9CtcjvOtRuL3rUTi9kML1vOtRuL3rUTi9CtcjvArXoz3rUTi9kML1vArXoz3rUTi9kML1vIaWnL3rUTg9CtcjvIaWnL3rUTg9kML1vArXoz3rUTg9CtcjvArXoz3rUTg9CtcjPIaWnL3rUTg9kML1PIaWnL3rUTg9CtcjPArXoz3rUTg9kML1PArXoz3rUTg9kML1vFyPwr2amZk9kML1vArXoz3rUTg9kML1vK1H4T2amZk9kML1vK1H4T2amZm9kML1vArXoz3rUTi9kML1vOtRuL3rUTi9kML1vIaWnL3rUTg9kML1vJDC9b3NzMw8kML1vOtRuL2wyJI8kML1vJDC9b2amZm9kML1PK1H4T2amZk9kML1PIaWnL3rUTg9kML1PFyPwr2amZk9kML1PJDC9b3NzMw8kML1POtRuL2wyJI8kML1PJDC9b2amZm9kML1POtRuL3rUTi9kML1PArXoz3rUTi9kML1PArXoz3rUTg9kML1PK1H4T2amZm9kML1PFyPwr2amZk9kML1vFyPwr2amZk9kML1PK1H4T2amZk9kML1vK1H4T2amZk9kML1vJDC9b2amZm9kML1PJDC9b2amZm9kML1vK1H4T2amZm9kML1PK1H4T2amZm9kML1vK1H4T2amZm9CtcjvK1H4T3rUTg9kML1vK1H4T2amZk9kML1PK1H4T2amZk9CtcjPK1H4T3rUTg9CtcjPK1H4T3rUTi9CtcjvK1H4T3rUTi9kML1PK1H4T2amZm9kML1vJDC9b3NzMw8kML1vFyPwr2amZk9kML1PJDC9b3NzMw8kML1PFyPwr2amZk9kML1vJDC9b2amZm9kML1vJDC9b3NzMw8kML1PJDC9b2amZm9kML1PJDC9b3NzMw8CtcjPOtRuL2wyJI8CtcjPOtRuL3rUTi9kML1POtRuL2wyJI8kML1POtRuL3rUTi9CtcjvArXoz3rUTg9CtcjvIaWnL3rUTg9CtcjvArXoz3rUTi9CtcjvOtRuL2wyJI8CtcjvOtRuL3rUTi9CtcjPIaWnL3rUTg9CtcjPArXoz3rUTg9CtcjPOtRuL2wyJI8CtcjPArXoz3rUTi9CtcjPOtRuL3rUTi9CtcjvK1H4T3rUTi9CtcjPK1H4T3rUTi93kEevKKU5j3rUTi93kEePKKU5j3rUTi9vOMNvB+F6z3rUTi9vOMNPB+F6z3rUTi9a7TnO/TC7z3rUTi9a7Tnu/TC7z3rUTi9CtejuyYE8z3rUTi9CtejOyYE8z3rUTi9oZ4pu+kP9T3rUTi9oZ4pO+kP9T3rUTi9AAAAAJDC9T3rUTi9a7Tnu/TC7z3rUTg9a7Tnu/TC7z3rUTi9CtejuyYE8z3rUTg9CtejuyYE8z3rUTi9vOMNPB+F6z3rUTg9a7TnO/TC7z3rUTg9vOMNPB+F6z3rUTi9a7TnO/TC7z3rUTi9CtcjPK1H4T3rUTg9CtcjvK1H4T3rUTg93kEePKKU5j3rUTg93kEevKKU5j3rUTg9vOMNPB+F6z3rUTg9vOMNvB+F6z3rUTg9a7TnO/TC7z3rUTg9a7Tnu/TC7z3rUTg9CtejOyYE8z3rUTg9CtejuyYE8z3rUTg9oZ4pO+kP9T3rUTg9oZ4pu+kP9T3rUTg9AAAAAJDC9T3rUTg9a7Tnu/TC7z3rUTg9vOMNvB+F6z3rUTg9a7Tnu/TC7z3rUTi9vOMNvB+F6z3rUTi93kEevKKU5j3rUTg9CtcjvK1H4T3rUTg93kEevKKU5j3rUTi9CtcjvK1H4T3rUTi9AAAAAJDC9T3rUTg9AAAAAJDC9T3rUTi9oZ4pO+kP9T3rUTg9oZ4pO+kP9T3rUTi9oZ4pO+kP9T3rUTg9oZ4pO+kP9T3rUTi9CtejOyYE8z3rUTg9CtejOyYE8z3rUTi93kEePKKU5j3rUTg9vOMNPB+F6z3rUTg93kEePKKU5j3rUTi9vOMNPB+F6z3rUTi9CtcjPK1H4T3rUTg93kEePKKU5j3rUTg9CtcjPK1H4T3rUTi93kEePKKU5j3rUTi9CtejOyYE8z3rUTg9CtejOyYE8z3rUTi9a7TnO/TC7z3rUTg9a7TnO/TC7z3rUTi9vOMNvB+F6z3rUTg93kEevKKU5j3rUTg9vOMNvB+F6z3rUTi93kEevKKU5j3rUTi9CtejuyYE8z3rUTg9CtejuyYE8z3rUTi9oZ4pu+kP9T3rUTg9oZ4pu+kP9T3rUTi9oZ4pu+kP9T3rUTg9oZ4pu+kP9T3rUTi9AAAAAJDC9T3rUTg9AAAAAJDC9T3rUTi9qar//wAA/7+pqv//AAD/v6mq//8AAP+/qar//wAA/7+pqv//AAD/v6mq//8AAP+/qar//wAA/7+pqv//AAD/v/9///////+//3///////7//f///////v/9///////+//38AAAAA/7//fwAAAAD/v/9/AAAAAP+//38AAAAA/7//f/9/////v/9//3////+//3//f////7//f/9/////v/9/AAAAAP+//38AAAAA/7//fwAAAAD/v/9/AAAAAP+//3//f////7//f/9/////v/9//3////+//3//f////7//////AAD/v/////8AAP+//////wAA/7//////AAD/v/////8AAP+//////wAA/7//////AAD/v/////8AAP+/AAD/f/9//78AAP9//3//vwAA/3//f/+/AAD/f/9//78AAP9//3//vwAA/3//f/+/AAD/f/9//78AAP9//3//vwAA/3//f/+/AAD/f/9//7////9//////////3/+////////f/7///////9//v///////3/+////////f/7/AID///9//v8AgP///3///wCA////f/////////9///////9//3////+//3//f////7//f/9/////v/9//3////+//////wAA/7//////AAD/v/////8AAP+//////wAA/7//f///////v/9///////+//3///////7//f////v//v/9////+//+//3///////7//f////v//v/9///////+//3+qKv///7//f6oq////v/9/qir///+//3+qKv///7//fwAAAAD/v/9/AAAAAP+//38AAAAA/7//fwAAAAD/v/9///////+//3///////7//f///////v/9///////+/AAD/fwAAAIAAAP9/AAAAgAAA/38AAACAAAD/fwAAAIAAAP9/AAAAgP///38AAACA////fwAAAID///9/AAAAgP///38AAACA////fwAAAID/////AAAAgP////8AAACA/////wAAAID/////AAAAgP////8AAACA/////wAAAID/////AAAAgP////8AAACA/////wAAAID/////AAAAgP////8AAACA/////wAAAID/////AAAAgP8//78AAACA/z//vwAAAIAlUSXRAAAAgCVRJdEAAACAJdHZrgAAAID/v/+/AAAAgCXR2a4AAACA/7//vwAAAID/f/9/AAAAgP9//38AAACA/3//fwAAAID/f/9/AAAAgP9//38AAACA/3//fwAAAID/f/9/AAAAgP9//38AAACA/3//fwAAAID/f/9/AAAAgP9//38AAACA/3//fwAAAID/f/9/AAAAgP8//78AAACA2S7ZrgAAAID/P/+/AAAAgNku2a4AAACADBsMmwAAAIDkDuOOAAAAgAwbDJsAAACA5A7jjgAAAID/f///AAAAgP9///8AAACADJvy5AAAAIAMm/LkAAAAgAyb8uQAAACADJvy5AAAAIDZriXRAAAAgNmuJdEAAACA8uQMmwAAAIAl0dmuAAAAgPLkDJsAAACAJdHZrgAAAIAa8eOOAAAAgPLkDJsAAACAGvHjjgAAAIDy5AybAAAAgNmuJdEAAACA2a4l0QAAAID/v/+/AAAAgP+//78AAACA2S7ZrgAAAIAMGwybAAAAgNku2a4AAACADBsMmwAAAIAlUSXRAAAAgCVRJdEAAACA8mTy5AAAAIDyZPLkAAAAgPJk8uQAAACA8mTy5AAAAID/f///AAAAgP9///8AAACA")
|
||||||
|
}, {
|
||||||
|
"aabb": AABB(-0.03, -0.12, -0.075, 0.06, 0.24, 0.15),
|
||||||
|
"attribute_data": PackedByteArray("XS6XP0T3Qj9dLpc/dxH6PyaTyT5E90I/JpPJPncR+j8mk8m+RPdCPyaTyb53Efo/XS6Xv0T3Qj9dLpe/dxH6P10ul7+US9o/XS6XvxaLRb8mk8m+lEvaPyaTyb4Wi0W/JpPJvhaLRb8mk8m+xmIxQF0ul78Wi0W/XS6Xv8ZiMUBdLpc/xmKRQCaTyT7GYpFAXS6XPyaTCcAmk8k+JpMJwF0ulz8Wi0W/XS6XP8ZiMUAmk8k+FotFvyaTyT7GYjFAJpPJvsZikUBdLpe/xmKRQCaTyb4mkwnAXS6XvyaTCcBdLpc/hlOAQCaTyT6GU4BAXS6XPyaTCcAmk8k+JpMJwCaTyb6GU4BAXS6Xv4ZTgEAmk8m+JpMJwF0ul78mkwnA9Pk8QF6vl0CLxeI/JpMJwPT5PEBUKlXA9Pk8wFQqVcCLxeK/JpMJwIvF4r/GYpFAi8XiP4ZTgEDw93s/XS63QCmXND/GYpFA9Pk8wF0ut0D0+TzAVCpVwIvF4r+GU4BA9Pk8wF6vl0Dw93u/XS63QCmXNL/GYpFA9Pk8QF0ut0CLxeI/xmKRQIvF4j8mkwnAi8XivyaTCcD0+TxAVCpVwF0ulz9er5dAXS6Xv16vl0BdLpc/VCpVwF0ul79UKlXAXS6XP10ut0BdLpe/XS63QF0ulz9UKlXAXS6Xv1QqVcBdLpe/6PP5vyaTyb7GYjFAXS6Xv/T5fEBdLpc/9Pl8QCaTyT7GYjFAJpPJPhaLRb8mk8m+FotFv10ulz/o8/m/XS6Xv+3gDkBdLpe/QIgBPV0ulz/t4A5AXS6XP0CIAT1dLpc/6PP5v10ulz/4+/0/XS6Xv+jz+b9dLpe/+Pv9PyaTyT6US9o/JpPJPhaLRb9dLpc/lEvaP10ulz8Wi0W/i8XiPyaTCcCLxeI/hlOAQIvF4r8mkwnAKZc0P8ZikUCLxeK/xmKRQIvF4r+GU4BAi8XivyaTCcAplzS/xmKRQIvF4j8mkwnAi8XiP8ZikUAmk8k+VCpVwCaTyb5UKlXA0bTCPtCvW8DRtMK+0K9bwKORrj6Iw2HAo5GuvojDYcDwiI6+cvtmwPCIjj5y+2bAJpNJPor8asAmk0m+ivxqwIOv0D3ugG3Ag6/Qve6AbcDxsKoOulxuwIvF4j+g4Mq/i8Xiv6Dgyr+LxeI/agjYv4vF4r9qCNi/i8Xiv+mZGMCLxeK/zS0fwIvF4j/pmRjAi8XiP80tH8Amk8k+VCpVwCaTyb5UKlXA0bTCPtCvW8DRtMK+0K9bwKORrj6Iw2HAo5GuvojDYcDwiI4+cvtmwPCIjr5y+2bAJpNJPor8asAmk0m+ivxqwIOv0D3ugG3Ag6/Qve6AbcAJafYNulxuwIvF4j/NLR/Ai8XiP+mZGMCLxeK/zS0fwIvF4r/pmRjAi8XiP0AVVsCLxeI/XIFPwIvF4r9AFVbAi8Xiv1yBT8CLxeK/QEXEPovF4j9ARcQ+i8Xiv2Dk+D6LxeI/YOT4PovF4r/4azW/i8XiP/hrNb+LxeK/aBwbv4vF4j9oHBu/i8Xiv0/HPMCLxeK/MltDwIvF4j9PxzzAi8XiPzJbQ8CLxeK/XIFPwIvF4r9AFVbAi8XiP1yBT8CLxeI/QBVWwIvF4r9qCNi/i8XiP2oI2L+LxeK/oODKv4vF4j+g4Mq/i8XiPzJbQ8CLxeI/T8c8wIvF4r8yW0PAi8Xiv0/HPMCLxeI/aBwbv4vF4r9oHBu/i8XiP/hrNb+LxeK/+Gs1v4vF4j9g5Pg+i8Xiv2Dk+D6LxeI/QEXEPovF4r9ARcQ+"),
|
||||||
|
"format": 34359742487,
|
||||||
|
"index_count": 18,
|
||||||
|
"index_data": PackedByteArray("VgBUAFUAVQBXAFYAVwBYAFYAWwBZAFoAWgBcAFsAXABdAFsA"),
|
||||||
|
"material": SubResource("StandardMaterial3D_757o3"),
|
||||||
|
"name": "darkMetal",
|
||||||
|
"primitive": 3,
|
||||||
|
"uv_scale": Vector4(0, 0, 0, 0),
|
||||||
|
"vertex_count": 168,
|
||||||
|
"vertex_data": PackedByteArray("kML1vIaWnL3rUTg9kML1vOtRuL2wyJI8CtcjvIaWnL3rUTg9CtcjvOtRuL2wyJI8CtcjPIaWnL3rUTg9CtcjPOtRuL2wyJI8kML1PIaWnL3rUTg9kML1POtRuL2wyJI8kML1vOtRuL2wyJI8kML1vOtRuL3rUTi9CtcjvOtRuL2wyJI8CtcjvOtRuL3rUTi9CtcjPArXoz3rUTi9CtcjPArXoz3rUTg9kML1PArXoz3rUTi9kML1PArXoz3rUTg9kML1POtRuL3rUTi9CtcjPOtRuL3rUTi9kML1PArXoz3rUTi9CtcjPArXoz3rUTi9kML1vArXoz3rUTi9kML1vArXoz3rUTg9CtcjvArXoz3rUTi9CtcjvArXoz3rUTg9CtcjvOtRuL3rUTi9kML1vOtRuL3rUTi9CtcjvArXoz3rUTi9kML1vArXoz3rUTi9kML1vIaWnL3rUTg9CtcjvIaWnL3rUTg9kML1vArXoz3rUTg9CtcjvArXoz3rUTg9CtcjPIaWnL3rUTg9kML1PIaWnL3rUTg9CtcjPArXoz3rUTg9kML1PArXoz3rUTg9kML1vFyPwr2amZk9kML1vArXoz3rUTg9kML1vK1H4T2amZk9kML1vK1H4T2amZm9kML1vArXoz3rUTi9kML1vOtRuL3rUTi9kML1vIaWnL3rUTg9kML1vJDC9b3NzMw8kML1vOtRuL2wyJI8kML1vJDC9b2amZm9kML1PK1H4T2amZk9kML1PIaWnL3rUTg9kML1PFyPwr2amZk9kML1PJDC9b3NzMw8kML1POtRuL2wyJI8kML1PJDC9b2amZm9kML1POtRuL3rUTi9kML1PArXoz3rUTi9kML1PArXoz3rUTg9kML1PK1H4T2amZm9kML1PFyPwr2amZk9kML1vFyPwr2amZk9kML1PK1H4T2amZk9kML1vK1H4T2amZk9kML1vJDC9b2amZm9kML1PJDC9b2amZm9kML1vK1H4T2amZm9kML1PK1H4T2amZm9kML1vK1H4T2amZm9CtcjvK1H4T3rUTg9kML1vK1H4T2amZk9kML1PK1H4T2amZk9CtcjPK1H4T3rUTg9CtcjPK1H4T3rUTi9CtcjvK1H4T3rUTi9kML1PK1H4T2amZm9kML1vJDC9b3NzMw8kML1vFyPwr2amZk9kML1PJDC9b3NzMw8kML1PFyPwr2amZk9kML1vJDC9b2amZm9kML1vJDC9b3NzMw8kML1PJDC9b2amZm9kML1PJDC9b3NzMw8CtcjPOtRuL2wyJI8CtcjPOtRuL3rUTi9kML1POtRuL2wyJI8kML1POtRuL3rUTi9CtcjvArXoz3rUTg9CtcjvIaWnL3rUTg9CtcjvArXoz3rUTi9CtcjvOtRuL2wyJI8CtcjvOtRuL3rUTi9CtcjPIaWnL3rUTg9CtcjPArXoz3rUTg9CtcjPOtRuL2wyJI8CtcjPArXoz3rUTi9CtcjPOtRuL3rUTi9CtcjvK1H4T3rUTi9CtcjPK1H4T3rUTi93kEevKKU5j3rUTi93kEePKKU5j3rUTi9vOMNvB+F6z3rUTi9vOMNPB+F6z3rUTi9a7TnO/TC7z3rUTi9a7Tnu/TC7z3rUTi9CtejuyYE8z3rUTi9CtejOyYE8z3rUTi9oZ4pu+kP9T3rUTi9oZ4pO+kP9T3rUTi9AAAAAJDC9T3rUTi9a7Tnu/TC7z3rUTg9a7Tnu/TC7z3rUTi9CtejuyYE8z3rUTg9CtejuyYE8z3rUTi9vOMNPB+F6z3rUTg9a7TnO/TC7z3rUTg9vOMNPB+F6z3rUTi9a7TnO/TC7z3rUTi9CtcjPK1H4T3rUTg9CtcjvK1H4T3rUTg93kEePKKU5j3rUTg93kEevKKU5j3rUTg9vOMNPB+F6z3rUTg9vOMNvB+F6z3rUTg9a7TnO/TC7z3rUTg9a7Tnu/TC7z3rUTg9CtejOyYE8z3rUTg9CtejuyYE8z3rUTg9oZ4pO+kP9T3rUTg9oZ4pu+kP9T3rUTg9AAAAAJDC9T3rUTg9a7Tnu/TC7z3rUTg9vOMNvB+F6z3rUTg9a7Tnu/TC7z3rUTi9vOMNvB+F6z3rUTi93kEevKKU5j3rUTg9CtcjvK1H4T3rUTg93kEevKKU5j3rUTi9CtcjvK1H4T3rUTi9AAAAAJDC9T3rUTg9AAAAAJDC9T3rUTi9oZ4pO+kP9T3rUTg9oZ4pO+kP9T3rUTi9oZ4pO+kP9T3rUTg9oZ4pO+kP9T3rUTi9CtejOyYE8z3rUTg9CtejOyYE8z3rUTi93kEePKKU5j3rUTg9vOMNPB+F6z3rUTg93kEePKKU5j3rUTi9vOMNPB+F6z3rUTi9CtcjPK1H4T3rUTg93kEePKKU5j3rUTg9CtcjPK1H4T3rUTi93kEePKKU5j3rUTi9CtejOyYE8z3rUTg9CtejOyYE8z3rUTi9a7TnO/TC7z3rUTg9a7TnO/TC7z3rUTi9vOMNvB+F6z3rUTg93kEevKKU5j3rUTg9vOMNvB+F6z3rUTi93kEevKKU5j3rUTi9CtejuyYE8z3rUTg9CtejuyYE8z3rUTi9oZ4pu+kP9T3rUTg9oZ4pu+kP9T3rUTi9oZ4pu+kP9T3rUTg9oZ4pu+kP9T3rUTi9AAAAAJDC9T3rUTg9AAAAAJDC9T3rUTi9qar//wAAAICpqv//AAAAgKmq//8AAACAqar//wAAAICpqv//AAAAgKmq//8AAACAqar//wAAAICpqv//AAAAgP9///8AAACA/3///wAAAID/f///AAAAgP9///8AAACA/38AAAAAAID/fwAAAAAAgP9/AAAAAACA/38AAAAAAID/f/9/AAAAgP9//38AAACA/3//fwAAAID/f/9/AAAAgP9/AAAAAACA/38AAAAAAID/fwAAAAAAgP9/AAAAAACA/3//fwAAAID/f/9/AAAAgP9//38AAACA/3//fwAAAID/////AAAAgP////8AAACA/////wAAAID/////AAAAgP////8AAACA/////wAAAID/////AAAAgP////8AAACAAAD/fwAAAIAAAP9/AAAAgAAA/38AAACAAAD/fwAAAIAAAP9/AAAAgAAA/38AAACAAAD/fwAAAIAAAP9/AAAAgAAA/38AAACAAAD/fwAAAID///9/AAAAgP///38AAACA////fwAAAID///9/AAAAgP///38AAACA////fwAAAID///9/AAAAgP///38AAACA////fwAAAID///9/AAAAgP9//38AAACA/3//fwAAAID/f/9/AAAAgP9//38AAACA/////wAAAID/////AAAAgP////8AAACA/////wAAAID/f///AAAAgP9///8AAACA/3///wAAAID/f///AAAAgP9///8AAACA/3///wAAAID/f///AAAAgP9///8AAACA/3+qKgAAAID/f6oqAAAAgP9/qioAAACA/3+qKgAAAID/fwAAAAAAgP9/AAAAAACA/38AAAAAAID/fwAAAAAAgP9///8AAACA/3///wAAAID/f///AAAAgP9///8AAACAAAD/f/9//78AAP9//3//vwAA/3//f/+/AAD/f/9//78AAP9//3//v////3/+////////f/////////9//v///////3//////////f///////////AAAAgP////8AAACA/////wAAAID/////AAAAgP////8AAACA/////wAAAID/////AAAAgP////8AAACA/////wAAAID/////AAAAgP////8AAACA/////wAAAID/////AAAAgP8//78AAACA/z//vwAAAIAlUSXRAAAAgCVRJdEAAACAJdHZrgAAAID/v/+/AAAAgCXR2a4AAACA/7//vwAAAID/f/9/AAAAgP9//38AAACA/3//fwAAAID/f/9/AAAAgP9//38AAACA/3//fwAAAID/f/9/AAAAgP9//38AAACA/3//fwAAAID/f/9/AAAAgP9//38AAACA/3//fwAAAID/f/9/AAAAgP8//78AAACA2S7ZrgAAAID/P/+/AAAAgNku2a4AAACADBsMmwAAAIDkDuOOAAAAgAwbDJsAAACA5A7jjgAAAID/f///AAAAgP9///8AAACADJvy5AAAAIAMm/LkAAAAgAyb8uQAAACADJvy5AAAAIDZriXRAAAAgNmuJdEAAACA8uQMmwAAAIAl0dmuAAAAgPLkDJsAAACAJdHZrgAAAIAa8eOOAAAAgPLkDJsAAACAGvHjjgAAAIDy5AybAAAAgNmuJdEAAACA2a4l0QAAAID/v/+/AAAAgP+//78AAACA2S7ZrgAAAIAMGwybAAAAgNku2a4AAACADBsMmwAAAIAlUSXRAAAAgCVRJdEAAACA8mTy5AAAAIDyZPLkAAAAgPJk8uQAAACA8mTy5AAAAID/f///AAAAgP9///8AAACA")
|
||||||
|
}, {
|
||||||
|
"aabb": AABB(-0.03, -0.12, -0.075, 0.06, 0.24, 0.15),
|
||||||
|
"attribute_data": PackedByteArray("XS6XP0T3Qj9dLpc/dxH6PyaTyT5E90I/JpPJPncR+j8mk8m+RPdCPyaTyb53Efo/XS6Xv0T3Qj9dLpe/dxH6P10ul7+US9o/XS6XvxaLRb8mk8m+lEvaPyaTyb4Wi0W/JpPJvhaLRb8mk8m+xmIxQF0ul78Wi0W/XS6Xv8ZiMUBdLpc/xmKRQCaTyT7GYpFAXS6XPyaTCcAmk8k+JpMJwF0ulz8Wi0W/XS6XP8ZiMUAmk8k+FotFvyaTyT7GYjFAJpPJvsZikUBdLpe/xmKRQCaTyb4mkwnAXS6XvyaTCcBdLpc/hlOAQCaTyT6GU4BAXS6XPyaTCcAmk8k+JpMJwCaTyb6GU4BAXS6Xv4ZTgEAmk8m+JpMJwF0ul78mkwnA9Pk8QF6vl0CLxeI/JpMJwPT5PEBUKlXA9Pk8wFQqVcCLxeK/JpMJwIvF4r/GYpFAi8XiP4ZTgEDw93s/XS63QCmXND/GYpFA9Pk8wF0ut0D0+TzAVCpVwIvF4r+GU4BA9Pk8wF6vl0Dw93u/XS63QCmXNL/GYpFA9Pk8QF0ut0CLxeI/xmKRQIvF4j8mkwnAi8XivyaTCcD0+TxAVCpVwF0ulz9er5dAXS6Xv16vl0BdLpc/VCpVwF0ul79UKlXAXS6XP10ut0BdLpe/XS63QF0ulz9UKlXAXS6Xv1QqVcBdLpe/6PP5vyaTyb7GYjFAXS6Xv/T5fEBdLpc/9Pl8QCaTyT7GYjFAJpPJPhaLRb8mk8m+FotFv10ulz/o8/m/XS6Xv+3gDkBdLpe/QIgBPV0ulz/t4A5AXS6XP0CIAT1dLpc/6PP5v10ulz/4+/0/XS6Xv+jz+b9dLpe/+Pv9PyaTyT6US9o/JpPJPhaLRb9dLpc/lEvaP10ulz8Wi0W/i8XiPyaTCcCLxeI/hlOAQIvF4r8mkwnAKZc0P8ZikUCLxeK/xmKRQIvF4r+GU4BAi8XivyaTCcAplzS/xmKRQIvF4j8mkwnAi8XiP8ZikUAmk8k+VCpVwCaTyb5UKlXA0bTCPtCvW8DRtMK+0K9bwKORrj6Iw2HAo5GuvojDYcDwiI6+cvtmwPCIjj5y+2bAJpNJPor8asAmk0m+ivxqwIOv0D3ugG3Ag6/Qve6AbcDxsKoOulxuwIvF4j+g4Mq/i8Xiv6Dgyr+LxeI/agjYv4vF4r9qCNi/i8Xiv+mZGMCLxeK/zS0fwIvF4j/pmRjAi8XiP80tH8Amk8k+VCpVwCaTyb5UKlXA0bTCPtCvW8DRtMK+0K9bwKORrj6Iw2HAo5GuvojDYcDwiI4+cvtmwPCIjr5y+2bAJpNJPor8asAmk0m+ivxqwIOv0D3ugG3Ag6/Qve6AbcAJafYNulxuwIvF4j/NLR/Ai8XiP+mZGMCLxeK/zS0fwIvF4r/pmRjAi8XiP0AVVsCLxeI/XIFPwIvF4r9AFVbAi8Xiv1yBT8CLxeK/QEXEPovF4j9ARcQ+i8Xiv2Dk+D6LxeI/YOT4PovF4r/4azW/i8XiP/hrNb+LxeK/aBwbv4vF4j9oHBu/i8Xiv0/HPMCLxeK/MltDwIvF4j9PxzzAi8XiPzJbQ8CLxeK/XIFPwIvF4r9AFVbAi8XiP1yBT8CLxeI/QBVWwIvF4r9qCNi/i8XiP2oI2L+LxeK/oODKv4vF4j+g4Mq/i8XiPzJbQ8CLxeI/T8c8wIvF4r8yW0PAi8Xiv0/HPMCLxeI/aBwbv4vF4r9oHBu/i8XiP/hrNb+LxeK/+Gs1v4vF4j9g5Pg+i8Xiv2Dk+D6LxeI/QEXEPovF4r9ARcQ+"),
|
||||||
|
"format": 34359742487,
|
||||||
|
"index_count": 138,
|
||||||
|
"index_data": PackedByteArray("YABeAF8AXwBhAGAAYQBiAGAAYQBjAGIAYwBkAGIAZABlAGIAZABmAGUAZABnAGYAZwBoAGYAZwBpAGgAaQBqAGgAbQBrAGwAbABuAG0AcQBvAHAAcAByAHEAdQBzAHQAdAB2AHUAdgB3AHUAdgB4AHcAeAB5AHcAeAB6AHkAegB7AHkAegB8AHsAfAB9AHsAfAB+AH0AfgB/AH0AggCAAIEAgQCDAIIAhgCEAIUAhQCHAIYAigCIAIkAiQCLAIoAjgCMAI0AjQCPAI4AkgCQAJEAkQCTAJIAlgCUAJUAlQCXAJYAmgCYAJkAmQCbAJoAngCcAJ0AnQCfAJ4AogCgAKEAoQCjAKIApgCkAKUApQCnAKYA"),
|
||||||
|
"material": SubResource("StandardMaterial3D_0y2bu"),
|
||||||
|
"name": "yellow",
|
||||||
|
"primitive": 3,
|
||||||
|
"uv_scale": Vector4(0, 0, 0, 0),
|
||||||
|
"vertex_count": 168,
|
||||||
|
"vertex_data": PackedByteArray("kML1vIaWnL3rUTg9kML1vOtRuL2wyJI8CtcjvIaWnL3rUTg9CtcjvOtRuL2wyJI8CtcjPIaWnL3rUTg9CtcjPOtRuL2wyJI8kML1PIaWnL3rUTg9kML1POtRuL2wyJI8kML1vOtRuL2wyJI8kML1vOtRuL3rUTi9CtcjvOtRuL2wyJI8CtcjvOtRuL3rUTi9CtcjPArXoz3rUTi9CtcjPArXoz3rUTg9kML1PArXoz3rUTi9kML1PArXoz3rUTg9kML1POtRuL3rUTi9CtcjPOtRuL3rUTi9kML1PArXoz3rUTi9CtcjPArXoz3rUTi9kML1vArXoz3rUTi9kML1vArXoz3rUTg9CtcjvArXoz3rUTi9CtcjvArXoz3rUTg9CtcjvOtRuL3rUTi9kML1vOtRuL3rUTi9CtcjvArXoz3rUTi9kML1vArXoz3rUTi9kML1vIaWnL3rUTg9CtcjvIaWnL3rUTg9kML1vArXoz3rUTg9CtcjvArXoz3rUTg9CtcjPIaWnL3rUTg9kML1PIaWnL3rUTg9CtcjPArXoz3rUTg9kML1PArXoz3rUTg9kML1vFyPwr2amZk9kML1vArXoz3rUTg9kML1vK1H4T2amZk9kML1vK1H4T2amZm9kML1vArXoz3rUTi9kML1vOtRuL3rUTi9kML1vIaWnL3rUTg9kML1vJDC9b3NzMw8kML1vOtRuL2wyJI8kML1vJDC9b2amZm9kML1PK1H4T2amZk9kML1PIaWnL3rUTg9kML1PFyPwr2amZk9kML1PJDC9b3NzMw8kML1POtRuL2wyJI8kML1PJDC9b2amZm9kML1POtRuL3rUTi9kML1PArXoz3rUTi9kML1PArXoz3rUTg9kML1PK1H4T2amZm9kML1PFyPwr2amZk9kML1vFyPwr2amZk9kML1PK1H4T2amZk9kML1vK1H4T2amZk9kML1vJDC9b2amZm9kML1PJDC9b2amZm9kML1vK1H4T2amZm9kML1PK1H4T2amZm9kML1vK1H4T2amZm9CtcjvK1H4T3rUTg9kML1vK1H4T2amZk9kML1PK1H4T2amZk9CtcjPK1H4T3rUTg9CtcjPK1H4T3rUTi9CtcjvK1H4T3rUTi9kML1PK1H4T2amZm9kML1vJDC9b3NzMw8kML1vFyPwr2amZk9kML1PJDC9b3NzMw8kML1PFyPwr2amZk9kML1vJDC9b2amZm9kML1vJDC9b3NzMw8kML1PJDC9b2amZm9kML1PJDC9b3NzMw8CtcjPOtRuL2wyJI8CtcjPOtRuL3rUTi9kML1POtRuL2wyJI8kML1POtRuL3rUTi9CtcjvArXoz3rUTg9CtcjvIaWnL3rUTg9CtcjvArXoz3rUTi9CtcjvOtRuL2wyJI8CtcjvOtRuL3rUTi9CtcjPIaWnL3rUTg9CtcjPArXoz3rUTg9CtcjPOtRuL2wyJI8CtcjPArXoz3rUTi9CtcjPOtRuL3rUTi9CtcjvK1H4T3rUTi9CtcjPK1H4T3rUTi93kEevKKU5j3rUTi93kEePKKU5j3rUTi9vOMNvB+F6z3rUTi9vOMNPB+F6z3rUTi9a7TnO/TC7z3rUTi9a7Tnu/TC7z3rUTi9CtejuyYE8z3rUTi9CtejOyYE8z3rUTi9oZ4pu+kP9T3rUTi9oZ4pO+kP9T3rUTi9AAAAAJDC9T3rUTi9a7Tnu/TC7z3rUTg9a7Tnu/TC7z3rUTi9CtejuyYE8z3rUTg9CtejuyYE8z3rUTi9vOMNPB+F6z3rUTg9a7TnO/TC7z3rUTg9vOMNPB+F6z3rUTi9a7TnO/TC7z3rUTi9CtcjPK1H4T3rUTg9CtcjvK1H4T3rUTg93kEePKKU5j3rUTg93kEevKKU5j3rUTg9vOMNPB+F6z3rUTg9vOMNvB+F6z3rUTg9a7TnO/TC7z3rUTg9a7Tnu/TC7z3rUTg9CtejOyYE8z3rUTg9CtejuyYE8z3rUTg9oZ4pO+kP9T3rUTg9oZ4pu+kP9T3rUTg9AAAAAJDC9T3rUTg9a7Tnu/TC7z3rUTg9vOMNvB+F6z3rUTg9a7Tnu/TC7z3rUTi9vOMNvB+F6z3rUTi93kEevKKU5j3rUTg9CtcjvK1H4T3rUTg93kEevKKU5j3rUTi9CtcjvK1H4T3rUTi9AAAAAJDC9T3rUTg9AAAAAJDC9T3rUTi9oZ4pO+kP9T3rUTg9oZ4pO+kP9T3rUTi9oZ4pO+kP9T3rUTg9oZ4pO+kP9T3rUTi9CtejOyYE8z3rUTg9CtejOyYE8z3rUTi93kEePKKU5j3rUTg9vOMNPB+F6z3rUTg93kEePKKU5j3rUTi9vOMNPB+F6z3rUTi9CtcjPK1H4T3rUTg93kEePKKU5j3rUTg9CtcjPK1H4T3rUTi93kEePKKU5j3rUTi9CtejOyYE8z3rUTg9CtejOyYE8z3rUTi9a7TnO/TC7z3rUTg9a7TnO/TC7z3rUTi9vOMNvB+F6z3rUTg93kEevKKU5j3rUTg9vOMNvB+F6z3rUTi93kEevKKU5j3rUTi9CtejuyYE8z3rUTg9CtejuyYE8z3rUTi9oZ4pu+kP9T3rUTg9oZ4pu+kP9T3rUTi9oZ4pu+kP9T3rUTg9oZ4pu+kP9T3rUTi9AAAAAJDC9T3rUTg9AAAAAJDC9T3rUTi9qar//wAAAICpqv//AAAAgKmq//8AAACAqar//wAAAICpqv//AAAAgKmq//8AAACAqar//wAAAICpqv//AAAAgP9///8AAACA/3///wAAAID/f///AAAAgP9///8AAACA/38AAAAAAID/fwAAAAAAgP9/AAAAAACA/38AAAAAAID/f/9/AAAAgP9//38AAACA/3//fwAAAID/f/9/AAAAgP9/AAAAAACA/38AAAAAAID/fwAAAAAAgP9/AAAAAACA/3//fwAAAID/f/9/AAAAgP9//38AAACA/3//fwAAAID/////AAAAgP////8AAACA/////wAAAID/////AAAAgP////8AAACA/////wAAAID/////AAAAgP////8AAACAAAD/fwAAAIAAAP9/AAAAgAAA/38AAACAAAD/fwAAAIAAAP9/AAAAgAAA/38AAACAAAD/fwAAAIAAAP9/AAAAgAAA/38AAACAAAD/fwAAAID///9/AAAAgP///38AAACA////fwAAAID///9/AAAAgP///38AAACA////fwAAAID///9/AAAAgP///38AAACA////fwAAAID///9/AAAAgP9//38AAACA/3//fwAAAID/f/9/AAAAgP9//38AAACA/////wAAAID/////AAAAgP////8AAACA/////wAAAID/f///AAAAgP9///8AAACA/3///wAAAID/f///AAAAgP9///8AAACA/3///wAAAID/f///AAAAgP9///8AAACA/3+qKgAAAID/f6oqAAAAgP9/qioAAACA/3+qKgAAAID/fwAAAAAAgP9/AAAAAACA/38AAAAAAID/fwAAAAAAgP9///8AAACA/3///wAAAID/f///AAAAgP9///8AAACAAAD/fwAAAIAAAP9/AAAAgAAA/38AAACAAAD/fwAAAIAAAP9/AAAAgP///38AAACA////fwAAAID///9/AAAAgP///38AAACA////fwAAAID/////AAD/v/////8AAP+//////wAA/7//////AAD/v/////8AAP+//////wAA/7//////AAD/v/////8AAP+//////wAA/7//////AAD/v/////8AAP+//////wAA/7//////AAD/v/8//7//f/+//z//v/9//78lUSXR/3//vyVRJdH/f/+/JdHZrv//////v/+//////yXR2a7//////7//v///////f/9/////v/9//3////+//3//f////7//f/9/////v/9//3////+//3//f////7//f/9/////v/9//3////+//3//f////7//f/9/////v/9//3////+//3//f////7//f/9/////v/8//7//f/+/2S7Zrv9//7//P/+//3//v9ku2a7/f/+/DBsMm/9//7/kDuOO/3//vwwbDJv/f/+/5A7jjv9//7//f/////////9/////////DJvy5P////8Mm/Lk/////wyb8uT/////DJvy5P/////ZriXR/////9muJdH/////8uQMm/////8l0dmu//////LkDJv/////JdHZrv////8a8eOO//////LkDJv/////GvHjjv/////y5Ayb/////9muJdH/////2a4l0f//////v/+///////+//7//////2S7Zrv9//78MGwyb/3//v9ku2a7/f/+/DBsMm/9//78lUSXR/3//vyVRJdH/f/+/8mTy5P9//7/yZPLk/3//v/Jk8uT/f/+/8mTy5P9//7//f////3//v/9/////f/+/")
|
||||||
|
}]
|
||||||
|
blend_shape_mode = 0
|
||||||
|
shadow_mesh = SubResource("ArrayMesh_bjg0s")
|
||||||
|
|
||||||
|
[sub_resource type="BoxShape3D" id="BoxShape3D_y1cnp"]
|
||||||
|
size = Vector3(0.0599088, 0.250772, 0.143523)
|
||||||
|
|
||||||
|
[node name="blasterL_Clip" type="RigidBody3D"]
|
||||||
|
collision_layer = 8
|
||||||
|
collision_mask = 5
|
||||||
|
script = ExtResource("1_mpf05")
|
||||||
|
weapon = SubResource("Resource_3vvaw")
|
||||||
|
TYPE = "Ammo"
|
||||||
|
|
||||||
|
[node name="clipA2" type="MeshInstance3D" parent="."]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1.21, 0, 0, 0, 1, 0, 0, 0)
|
||||||
|
mesh = SubResource("ArrayMesh_wf2rx")
|
||||||
|
skeleton = NodePath("")
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
|
||||||
|
shape = SubResource("BoxShape3D_y1cnp")
|
||||||
@@ -0,0 +1,124 @@
|
|||||||
|
[gd_scene load_steps=11 format=4 uid="uid://dl236agqx8rjp"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://deaf6cmuofa0" path="res://client/template/scripts/Weapon_State_Machine/PickUp Weapons/Weapon_Pick_Up.gd" id="1_6xwda"]
|
||||||
|
[ext_resource type="Script" uid="uid://bw4j1fbww4k8s" path="res://client/template/scripts/Weapon_State_Machine/WeaponSlot.gd" id="2_qrntt"]
|
||||||
|
[ext_resource type="Resource" uid="uid://yc1f2j7pl4vr" path="res://client/template/scripts/Weapon_State_Machine/Weapon_Resources/blasterI.tres" id="3_ot8uw"]
|
||||||
|
|
||||||
|
[sub_resource type="Resource" id="Resource_yxf5f"]
|
||||||
|
resource_local_to_scene = true
|
||||||
|
script = ExtResource("2_qrntt")
|
||||||
|
weapon = ExtResource("3_ot8uw")
|
||||||
|
current_ammo = 30
|
||||||
|
reserve_ammo = 0
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_n3ik4"]
|
||||||
|
resource_name = "metal"
|
||||||
|
vertex_color_use_as_albedo = true
|
||||||
|
albedo_color = Color(0.904365, 0.914141, 0.944534, 1)
|
||||||
|
metallic = 1.0
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_fil5e"]
|
||||||
|
resource_name = "darkMetal"
|
||||||
|
vertex_color_use_as_albedo = true
|
||||||
|
albedo_color = Color(0.793075, 0.81829, 0.89044, 1)
|
||||||
|
metallic = 1.0
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_bfdxb"]
|
||||||
|
resource_name = "yellow"
|
||||||
|
vertex_color_use_as_albedo = true
|
||||||
|
albedo_color = Color(0.998274, 0.894448, 0.505969, 1)
|
||||||
|
metallic = 1.0
|
||||||
|
|
||||||
|
[sub_resource type="ArrayMesh" id="ArrayMesh_j3k8o"]
|
||||||
|
_surfaces = [{
|
||||||
|
"aabb": AABB(-0.03, -0.12, -0.075, 0.06, 0.24, 0.15),
|
||||||
|
"format": 34359742465,
|
||||||
|
"index_count": 168,
|
||||||
|
"index_data": PackedByteArray("AgAAAAEAAQADAAIABgAEAAUABQAHAAYAAwABAAgACAAJAAMADAAKAAsACwANAAwADAAOAA8ADwAKAAwAEgAQABEAEQATABIAEgAJAAgACAAQABIAEQAAAAIAAgATABEACwAEAAYABgANAAsAFQAUABEAEQAWABUAEQAQABYAEAAIABYAAAARABQAFAAXAAAAFwABAAAAFwAYAAEAGAAIAAEAGAAWAAgAGgAZAAYABgAbABoABgAHABsABwAcABsABwAOABwADgAMABwADQAGABkAGQAdAA0AHQAMAA0AHQAcAAwAGQAaABQAFAAVABkAFgAYABwAHAAdABYAFQAWAB4AHgAZABUAHgAfABkAHwAgABkAIQAeABYAFgAdACEAHQAgACEAHQAZACAAGwAXABQAFAAaABsAHAAYABcAFwAbABwABwAFAA8ADwAOAAcA"),
|
||||||
|
"name": "metal",
|
||||||
|
"primitive": 3,
|
||||||
|
"uv_scale": Vector4(0, 0, 0, 0),
|
||||||
|
"vertex_count": 56,
|
||||||
|
"vertex_data": PackedByteArray("kML1vIaWnL3rUTg9kML1vOtRuL2wyJI8CtcjvIaWnL3rUTg9CtcjvOtRuL2wyJI8CtcjPIaWnL3rUTg9CtcjPOtRuL2wyJI8kML1PIaWnL3rUTg9kML1POtRuL2wyJI8kML1vOtRuL3rUTi9CtcjvOtRuL3rUTi9CtcjPArXoz3rUTi9CtcjPArXoz3rUTg9kML1PArXoz3rUTi9kML1PArXoz3rUTg9kML1POtRuL3rUTi9CtcjPOtRuL3rUTi9kML1vArXoz3rUTi9kML1vArXoz3rUTg9CtcjvArXoz3rUTi9CtcjvArXoz3rUTg9kML1vFyPwr2amZk9kML1vK1H4T2amZk9kML1vK1H4T2amZm9kML1vJDC9b3NzMw8kML1vJDC9b2amZm9kML1PK1H4T2amZk9kML1PFyPwr2amZk9kML1PJDC9b3NzMw8kML1PJDC9b2amZm9kML1PK1H4T2amZm9CtcjvK1H4T3rUTg9CtcjPK1H4T3rUTg9CtcjPK1H4T3rUTi9CtcjvK1H4T3rUTi93kEevKKU5j3rUTi93kEePKKU5j3rUTi9vOMNvB+F6z3rUTi9vOMNPB+F6z3rUTi9a7TnO/TC7z3rUTi9a7Tnu/TC7z3rUTi9CtejuyYE8z3rUTi9CtejOyYE8z3rUTi9oZ4pu+kP9T3rUTi9oZ4pO+kP9T3rUTi9AAAAAJDC9T3rUTi9a7Tnu/TC7z3rUTg9CtejuyYE8z3rUTg9vOMNPB+F6z3rUTg9a7TnO/TC7z3rUTg93kEePKKU5j3rUTg93kEevKKU5j3rUTg9vOMNvB+F6z3rUTg9CtejOyYE8z3rUTg9oZ4pO+kP9T3rUTg9oZ4pu+kP9T3rUTg9AAAAAJDC9T3rUTg9")
|
||||||
|
}, {
|
||||||
|
"aabb": AABB(-0.03, -0.12, -0.075, 0.06, 0.24, 0.15),
|
||||||
|
"format": 34359742465,
|
||||||
|
"index_count": 18,
|
||||||
|
"index_data": PackedByteArray("EgATAAIAAgADABIAAwAJABIABQAEAAsACwAKAAUACgAPAAUA"),
|
||||||
|
"name": "darkMetal",
|
||||||
|
"primitive": 3,
|
||||||
|
"uv_scale": Vector4(0, 0, 0, 0),
|
||||||
|
"vertex_count": 56,
|
||||||
|
"vertex_data": PackedByteArray("kML1vIaWnL3rUTg9kML1vOtRuL2wyJI8CtcjvIaWnL3rUTg9CtcjvOtRuL2wyJI8CtcjPIaWnL3rUTg9CtcjPOtRuL2wyJI8kML1PIaWnL3rUTg9kML1POtRuL2wyJI8kML1vOtRuL3rUTi9CtcjvOtRuL3rUTi9CtcjPArXoz3rUTi9CtcjPArXoz3rUTg9kML1PArXoz3rUTi9kML1PArXoz3rUTg9kML1POtRuL3rUTi9CtcjPOtRuL3rUTi9kML1vArXoz3rUTi9kML1vArXoz3rUTg9CtcjvArXoz3rUTi9CtcjvArXoz3rUTg9kML1vFyPwr2amZk9kML1vK1H4T2amZk9kML1vK1H4T2amZm9kML1vJDC9b3NzMw8kML1vJDC9b2amZm9kML1PK1H4T2amZk9kML1PFyPwr2amZk9kML1PJDC9b3NzMw8kML1PJDC9b2amZm9kML1PK1H4T2amZm9CtcjvK1H4T3rUTg9CtcjPK1H4T3rUTg9CtcjPK1H4T3rUTi9CtcjvK1H4T3rUTi93kEevKKU5j3rUTi93kEePKKU5j3rUTi9vOMNvB+F6z3rUTi9vOMNPB+F6z3rUTi9a7TnO/TC7z3rUTi9a7Tnu/TC7z3rUTi9CtejuyYE8z3rUTi9CtejOyYE8z3rUTi9oZ4pu+kP9T3rUTi9oZ4pO+kP9T3rUTi9AAAAAJDC9T3rUTi9a7Tnu/TC7z3rUTg9CtejuyYE8z3rUTg9vOMNPB+F6z3rUTg9a7TnO/TC7z3rUTg93kEePKKU5j3rUTg93kEevKKU5j3rUTg9vOMNvB+F6z3rUTg9CtejOyYE8z3rUTg9oZ4pO+kP9T3rUTg9oZ4pu+kP9T3rUTg9AAAAAJDC9T3rUTg9")
|
||||||
|
}, {
|
||||||
|
"aabb": AABB(-0.03, -0.12, -0.075, 0.06, 0.24, 0.15),
|
||||||
|
"format": 34359742465,
|
||||||
|
"index_count": 138,
|
||||||
|
"index_data": PackedByteArray("IgAhACAAIAAjACIAIwAkACIAIwAlACQAJQAmACQAJgAnACQAJgAoACcAJgApACgAKQAqACgAKQArACoAKwAsACoALgAtACcAJwAoAC4AJQAvADAAMAAmACUAMQAfAB4AHgAyADEAMgAvADEAMgAzAC8AMwAwAC8AMwAtADAALQA0ADAALQAuADQALgA1ADQALgA2ADUANgA3ADUAJwAtADMAMwAkACcAIgAyAB4AHgAhACIANQA3ACwALAArADUANAA1ACsAKwApADQAIwAxAC8ALwAlACMAIAAfADEAMQAjACAAMAA0ACkAKQAmADAAJAAzADIAMgAiACQANgAuACgAKAAqADYANwA2ACoAKgAsADcA"),
|
||||||
|
"name": "yellow",
|
||||||
|
"primitive": 3,
|
||||||
|
"uv_scale": Vector4(0, 0, 0, 0),
|
||||||
|
"vertex_count": 56,
|
||||||
|
"vertex_data": PackedByteArray("kML1vIaWnL3rUTg9kML1vOtRuL2wyJI8CtcjvIaWnL3rUTg9CtcjvOtRuL2wyJI8CtcjPIaWnL3rUTg9CtcjPOtRuL2wyJI8kML1PIaWnL3rUTg9kML1POtRuL2wyJI8kML1vOtRuL3rUTi9CtcjvOtRuL3rUTi9CtcjPArXoz3rUTi9CtcjPArXoz3rUTg9kML1PArXoz3rUTi9kML1PArXoz3rUTg9kML1POtRuL3rUTi9CtcjPOtRuL3rUTi9kML1vArXoz3rUTi9kML1vArXoz3rUTg9CtcjvArXoz3rUTi9CtcjvArXoz3rUTg9kML1vFyPwr2amZk9kML1vK1H4T2amZk9kML1vK1H4T2amZm9kML1vJDC9b3NzMw8kML1vJDC9b2amZm9kML1PK1H4T2amZk9kML1PFyPwr2amZk9kML1PJDC9b3NzMw8kML1PJDC9b2amZm9kML1PK1H4T2amZm9CtcjvK1H4T3rUTg9CtcjPK1H4T3rUTg9CtcjPK1H4T3rUTi9CtcjvK1H4T3rUTi93kEevKKU5j3rUTi93kEePKKU5j3rUTi9vOMNvB+F6z3rUTi9vOMNPB+F6z3rUTi9a7TnO/TC7z3rUTi9a7Tnu/TC7z3rUTi9CtejuyYE8z3rUTi9CtejOyYE8z3rUTi9oZ4pu+kP9T3rUTi9oZ4pO+kP9T3rUTi9AAAAAJDC9T3rUTi9a7Tnu/TC7z3rUTg9CtejuyYE8z3rUTg9vOMNPB+F6z3rUTg9a7TnO/TC7z3rUTg93kEePKKU5j3rUTg93kEevKKU5j3rUTg9vOMNvB+F6z3rUTg9CtejOyYE8z3rUTg9oZ4pO+kP9T3rUTg9oZ4pu+kP9T3rUTg9AAAAAJDC9T3rUTg9")
|
||||||
|
}]
|
||||||
|
blend_shape_mode = 0
|
||||||
|
|
||||||
|
[sub_resource type="ArrayMesh" id="ArrayMesh_py3xv"]
|
||||||
|
resource_name = "clipA_Mesh clipA"
|
||||||
|
_surfaces = [{
|
||||||
|
"aabb": AABB(-0.03, -0.12, -0.075, 0.06, 0.24, 0.15),
|
||||||
|
"attribute_data": PackedByteArray("XS6XP0T3Qj9dLpc/dxH6PyaTyT5E90I/JpPJPncR+j8mk8m+RPdCPyaTyb53Efo/XS6Xv0T3Qj9dLpe/dxH6P10ul7+US9o/XS6XvxaLRb8mk8m+lEvaPyaTyb4Wi0W/JpPJvhaLRb8mk8m+xmIxQF0ul78Wi0W/XS6Xv8ZiMUBdLpc/xmKRQCaTyT7GYpFAXS6XPyaTCcAmk8k+JpMJwF0ulz8Wi0W/XS6XP8ZiMUAmk8k+FotFvyaTyT7GYjFAJpPJvsZikUBdLpe/xmKRQCaTyb4mkwnAXS6XvyaTCcBdLpc/hlOAQCaTyT6GU4BAXS6XPyaTCcAmk8k+JpMJwCaTyb6GU4BAXS6Xv4ZTgEAmk8m+JpMJwF0ul78mkwnA9Pk8QF6vl0CLxeI/JpMJwPT5PEBUKlXA9Pk8wFQqVcCLxeK/JpMJwIvF4r/GYpFAi8XiP4ZTgEDw93s/XS63QCmXND/GYpFA9Pk8wF0ut0D0+TzAVCpVwIvF4r+GU4BA9Pk8wF6vl0Dw93u/XS63QCmXNL/GYpFA9Pk8QF0ut0CLxeI/xmKRQIvF4j8mkwnAi8XivyaTCcD0+TxAVCpVwF0ulz9er5dAXS6Xv16vl0BdLpc/VCpVwF0ul79UKlXAXS6XP10ut0BdLpe/XS63QF0ulz9UKlXAXS6Xv1QqVcBdLpe/6PP5vyaTyb7GYjFAXS6Xv/T5fEBdLpc/9Pl8QCaTyT7GYjFAJpPJPhaLRb8mk8m+FotFv10ulz/o8/m/XS6Xv+3gDkBdLpe/QIgBPV0ulz/t4A5AXS6XP0CIAT1dLpc/6PP5v10ulz/4+/0/XS6Xv+jz+b9dLpe/+Pv9PyaTyT6US9o/JpPJPhaLRb9dLpc/lEvaP10ulz8Wi0W/i8XiPyaTCcCLxeI/hlOAQIvF4r8mkwnAKZc0P8ZikUCLxeK/xmKRQIvF4r+GU4BAi8XivyaTCcAplzS/xmKRQIvF4j8mkwnAi8XiP8ZikUAmk8k+VCpVwCaTyb5UKlXA0bTCPtCvW8DRtMK+0K9bwKORrj6Iw2HAo5GuvojDYcDwiI6+cvtmwPCIjj5y+2bAJpNJPor8asAmk0m+ivxqwIOv0D3ugG3Ag6/Qve6AbcDxsKoOulxuwIvF4j+g4Mq/i8Xiv6Dgyr+LxeI/agjYv4vF4r9qCNi/i8Xiv+mZGMCLxeK/zS0fwIvF4j/pmRjAi8XiP80tH8Amk8k+VCpVwCaTyb5UKlXA0bTCPtCvW8DRtMK+0K9bwKORrj6Iw2HAo5GuvojDYcDwiI4+cvtmwPCIjr5y+2bAJpNJPor8asAmk0m+ivxqwIOv0D3ugG3Ag6/Qve6AbcAJafYNulxuwIvF4j/NLR/Ai8XiP+mZGMCLxeK/zS0fwIvF4r/pmRjAi8XiP0AVVsCLxeI/XIFPwIvF4r9AFVbAi8Xiv1yBT8CLxeK/QEXEPovF4j9ARcQ+i8Xiv2Dk+D6LxeI/YOT4PovF4r/4azW/i8XiP/hrNb+LxeK/aBwbv4vF4j9oHBu/i8Xiv0/HPMCLxeK/MltDwIvF4j9PxzzAi8XiPzJbQ8CLxeK/XIFPwIvF4r9AFVbAi8XiP1yBT8CLxeI/QBVWwIvF4r9qCNi/i8XiP2oI2L+LxeK/oODKv4vF4j+g4Mq/i8XiPzJbQ8CLxeI/T8c8wIvF4r8yW0PAi8Xiv0/HPMCLxeI/aBwbv4vF4r9oHBu/i8XiP/hrNb+LxeK/+Gs1v4vF4j9g5Pg+i8Xiv2Dk+D6LxeI/QEXEPovF4r9ARcQ+"),
|
||||||
|
"format": 34359742487,
|
||||||
|
"index_count": 168,
|
||||||
|
"index_data": PackedByteArray("AgAAAAEAAQADAAIABgAEAAUABQAHAAYACgAIAAkACQALAAoADgAMAA0ADQAPAA4AEgAQABEAEQATABIAFgAUABUAFQAXABYAGgAYABkAGQAbABoAHgAcAB0AHQAfAB4AIgAgACEAIQAjACIAJgAkACUAJQAnACYAJQAoACcAKAApACcAKgAlACQAJAArACoAKwAsACoAKwAtACwALQApACwALQAnACkAMAAuAC8ALwAxADAALwAyADEAMgAzADEAMgA0ADMANAA1ADMANgAvAC4ALgA3ADYANwA1ADYANwAzADUAOgA4ADkAOQA7ADoAPgA8AD0APQA/AD4AQgBAAEEAQQBDAEIAQQBEAEMARABFAEMARgBBAEAAQABHAEYARwBFAEYARwBDAEUASgBIAEkASQBLAEoATgBMAE0ATQBPAE4AUgBQAFEAUQBTAFIA"),
|
||||||
|
"material": SubResource("StandardMaterial3D_n3ik4"),
|
||||||
|
"name": "metal",
|
||||||
|
"primitive": 3,
|
||||||
|
"uv_scale": Vector4(0, 0, 0, 0),
|
||||||
|
"vertex_count": 168,
|
||||||
|
"vertex_data": PackedByteArray("kML1vIaWnL3rUTg9kML1vOtRuL2wyJI8CtcjvIaWnL3rUTg9CtcjvOtRuL2wyJI8CtcjPIaWnL3rUTg9CtcjPOtRuL2wyJI8kML1PIaWnL3rUTg9kML1POtRuL2wyJI8kML1vOtRuL2wyJI8kML1vOtRuL3rUTi9CtcjvOtRuL2wyJI8CtcjvOtRuL3rUTi9CtcjPArXoz3rUTi9CtcjPArXoz3rUTg9kML1PArXoz3rUTi9kML1PArXoz3rUTg9kML1POtRuL3rUTi9CtcjPOtRuL3rUTi9kML1PArXoz3rUTi9CtcjPArXoz3rUTi9kML1vArXoz3rUTi9kML1vArXoz3rUTg9CtcjvArXoz3rUTi9CtcjvArXoz3rUTg9CtcjvOtRuL3rUTi9kML1vOtRuL3rUTi9CtcjvArXoz3rUTi9kML1vArXoz3rUTi9kML1vIaWnL3rUTg9CtcjvIaWnL3rUTg9kML1vArXoz3rUTg9CtcjvArXoz3rUTg9CtcjPIaWnL3rUTg9kML1PIaWnL3rUTg9CtcjPArXoz3rUTg9kML1PArXoz3rUTg9kML1vFyPwr2amZk9kML1vArXoz3rUTg9kML1vK1H4T2amZk9kML1vK1H4T2amZm9kML1vArXoz3rUTi9kML1vOtRuL3rUTi9kML1vIaWnL3rUTg9kML1vJDC9b3NzMw8kML1vOtRuL2wyJI8kML1vJDC9b2amZm9kML1PK1H4T2amZk9kML1PIaWnL3rUTg9kML1PFyPwr2amZk9kML1PJDC9b3NzMw8kML1POtRuL2wyJI8kML1PJDC9b2amZm9kML1POtRuL3rUTi9kML1PArXoz3rUTi9kML1PArXoz3rUTg9kML1PK1H4T2amZm9kML1PFyPwr2amZk9kML1vFyPwr2amZk9kML1PK1H4T2amZk9kML1vK1H4T2amZk9kML1vJDC9b2amZm9kML1PJDC9b2amZm9kML1vK1H4T2amZm9kML1PK1H4T2amZm9kML1vK1H4T2amZm9CtcjvK1H4T3rUTg9kML1vK1H4T2amZk9kML1PK1H4T2amZk9CtcjPK1H4T3rUTg9CtcjPK1H4T3rUTi9CtcjvK1H4T3rUTi9kML1PK1H4T2amZm9kML1vJDC9b3NzMw8kML1vFyPwr2amZk9kML1PJDC9b3NzMw8kML1PFyPwr2amZk9kML1vJDC9b2amZm9kML1vJDC9b3NzMw8kML1PJDC9b2amZm9kML1PJDC9b3NzMw8CtcjPOtRuL2wyJI8CtcjPOtRuL3rUTi9kML1POtRuL2wyJI8kML1POtRuL3rUTi9CtcjvArXoz3rUTg9CtcjvIaWnL3rUTg9CtcjvArXoz3rUTi9CtcjvOtRuL2wyJI8CtcjvOtRuL3rUTi9CtcjPIaWnL3rUTg9CtcjPArXoz3rUTg9CtcjPOtRuL2wyJI8CtcjPArXoz3rUTi9CtcjPOtRuL3rUTi9CtcjvK1H4T3rUTi9CtcjPK1H4T3rUTi93kEevKKU5j3rUTi93kEePKKU5j3rUTi9vOMNvB+F6z3rUTi9vOMNPB+F6z3rUTi9a7TnO/TC7z3rUTi9a7Tnu/TC7z3rUTi9CtejuyYE8z3rUTi9CtejOyYE8z3rUTi9oZ4pu+kP9T3rUTi9oZ4pO+kP9T3rUTi9AAAAAJDC9T3rUTi9a7Tnu/TC7z3rUTg9a7Tnu/TC7z3rUTi9CtejuyYE8z3rUTg9CtejuyYE8z3rUTi9vOMNPB+F6z3rUTg9a7TnO/TC7z3rUTg9vOMNPB+F6z3rUTi9a7TnO/TC7z3rUTi9CtcjPK1H4T3rUTg9CtcjvK1H4T3rUTg93kEePKKU5j3rUTg93kEevKKU5j3rUTg9vOMNPB+F6z3rUTg9vOMNvB+F6z3rUTg9a7TnO/TC7z3rUTg9a7Tnu/TC7z3rUTg9CtejOyYE8z3rUTg9CtejuyYE8z3rUTg9oZ4pO+kP9T3rUTg9oZ4pu+kP9T3rUTg9AAAAAJDC9T3rUTg9a7Tnu/TC7z3rUTg9vOMNvB+F6z3rUTg9a7Tnu/TC7z3rUTi9vOMNvB+F6z3rUTi93kEevKKU5j3rUTg9CtcjvK1H4T3rUTg93kEevKKU5j3rUTi9CtcjvK1H4T3rUTi9AAAAAJDC9T3rUTg9AAAAAJDC9T3rUTi9oZ4pO+kP9T3rUTg9oZ4pO+kP9T3rUTi9oZ4pO+kP9T3rUTg9oZ4pO+kP9T3rUTi9CtejOyYE8z3rUTg9CtejOyYE8z3rUTi93kEePKKU5j3rUTg9vOMNPB+F6z3rUTg93kEePKKU5j3rUTi9vOMNPB+F6z3rUTi9CtcjPK1H4T3rUTg93kEePKKU5j3rUTg9CtcjPK1H4T3rUTi93kEePKKU5j3rUTi9CtejOyYE8z3rUTg9CtejOyYE8z3rUTi9a7TnO/TC7z3rUTg9a7TnO/TC7z3rUTi9vOMNvB+F6z3rUTg93kEevKKU5j3rUTg9vOMNvB+F6z3rUTi93kEevKKU5j3rUTi9CtejuyYE8z3rUTg9CtejuyYE8z3rUTi9oZ4pu+kP9T3rUTg9oZ4pu+kP9T3rUTi9oZ4pu+kP9T3rUTg9oZ4pu+kP9T3rUTi9AAAAAJDC9T3rUTg9AAAAAJDC9T3rUTi9qar//wAA/7+pqv//AAD/v6mq//8AAP+/qar//wAA/7+pqv//AAD/v6mq//8AAP+/qar//wAA/7+pqv//AAD/v/9///////+//3///////7//f///////v/9///////+//38AAAAA/7//fwAAAAD/v/9/AAAAAP+//38AAAAA/7//f/9/////v/9//3////+//3//f////7//f/9/////v/9/AAAAAP+//38AAAAA/7//fwAAAAD/v/9/AAAAAP+//3//f////7//f/9/////v/9//3////+//3//f////7//////AAD/v/////8AAP+//////wAA/7//////AAD/v/////8AAP+//////wAA/7//////AAD/v/////8AAP+/AAD/f/9//78AAP9//3//vwAA/3//f/+/AAD/f/9//78AAP9//3//vwAA/3//f/+/AAD/f/9//78AAP9//3//vwAA/3//f/+/AAD/f/9//7////9//////////3/+////////f/7///////9//v///////3/+////////f/7/AID///9//v8AgP///3///wCA////f/////////9///////9//3////+//3//f////7//f/9/////v/9//3////+//////wAA/7//////AAD/v/////8AAP+//////wAA/7//f///////v/9///////+//3///////7//f////v//v/9////+//+//3///////7//f////v//v/9///////+//3+qKv///7//f6oq////v/9/qir///+//3+qKv///7//fwAAAAD/v/9/AAAAAP+//38AAAAA/7//fwAAAAD/v/9///////+//3///////7//f///////v/9///////+/AAD/fwAAAIAAAP9/AAAAgAAA/38AAACAAAD/fwAAAIAAAP9/AAAAgP///38AAACA////fwAAAID///9/AAAAgP///38AAACA////fwAAAID/////AAAAgP////8AAACA/////wAAAID/////AAAAgP////8AAACA/////wAAAID/////AAAAgP////8AAACA/////wAAAID/////AAAAgP////8AAACA/////wAAAID/////AAAAgP8//78AAACA/z//vwAAAIAlUSXRAAAAgCVRJdEAAACAJdHZrgAAAID/v/+/AAAAgCXR2a4AAACA/7//vwAAAID/f/9/AAAAgP9//38AAACA/3//fwAAAID/f/9/AAAAgP9//38AAACA/3//fwAAAID/f/9/AAAAgP9//38AAACA/3//fwAAAID/f/9/AAAAgP9//38AAACA/3//fwAAAID/f/9/AAAAgP8//78AAACA2S7ZrgAAAID/P/+/AAAAgNku2a4AAACADBsMmwAAAIDkDuOOAAAAgAwbDJsAAACA5A7jjgAAAID/f///AAAAgP9///8AAACADJvy5AAAAIAMm/LkAAAAgAyb8uQAAACADJvy5AAAAIDZriXRAAAAgNmuJdEAAACA8uQMmwAAAIAl0dmuAAAAgPLkDJsAAACAJdHZrgAAAIAa8eOOAAAAgPLkDJsAAACAGvHjjgAAAIDy5AybAAAAgNmuJdEAAACA2a4l0QAAAID/v/+/AAAAgP+//78AAACA2S7ZrgAAAIAMGwybAAAAgNku2a4AAACADBsMmwAAAIAlUSXRAAAAgCVRJdEAAACA8mTy5AAAAIDyZPLkAAAAgPJk8uQAAACA8mTy5AAAAID/f///AAAAgP9///8AAACA")
|
||||||
|
}, {
|
||||||
|
"aabb": AABB(-0.03, -0.12, -0.075, 0.06, 0.24, 0.15),
|
||||||
|
"attribute_data": PackedByteArray("XS6XP0T3Qj9dLpc/dxH6PyaTyT5E90I/JpPJPncR+j8mk8m+RPdCPyaTyb53Efo/XS6Xv0T3Qj9dLpe/dxH6P10ul7+US9o/XS6XvxaLRb8mk8m+lEvaPyaTyb4Wi0W/JpPJvhaLRb8mk8m+xmIxQF0ul78Wi0W/XS6Xv8ZiMUBdLpc/xmKRQCaTyT7GYpFAXS6XPyaTCcAmk8k+JpMJwF0ulz8Wi0W/XS6XP8ZiMUAmk8k+FotFvyaTyT7GYjFAJpPJvsZikUBdLpe/xmKRQCaTyb4mkwnAXS6XvyaTCcBdLpc/hlOAQCaTyT6GU4BAXS6XPyaTCcAmk8k+JpMJwCaTyb6GU4BAXS6Xv4ZTgEAmk8m+JpMJwF0ul78mkwnA9Pk8QF6vl0CLxeI/JpMJwPT5PEBUKlXA9Pk8wFQqVcCLxeK/JpMJwIvF4r/GYpFAi8XiP4ZTgEDw93s/XS63QCmXND/GYpFA9Pk8wF0ut0D0+TzAVCpVwIvF4r+GU4BA9Pk8wF6vl0Dw93u/XS63QCmXNL/GYpFA9Pk8QF0ut0CLxeI/xmKRQIvF4j8mkwnAi8XivyaTCcD0+TxAVCpVwF0ulz9er5dAXS6Xv16vl0BdLpc/VCpVwF0ul79UKlXAXS6XP10ut0BdLpe/XS63QF0ulz9UKlXAXS6Xv1QqVcBdLpe/6PP5vyaTyb7GYjFAXS6Xv/T5fEBdLpc/9Pl8QCaTyT7GYjFAJpPJPhaLRb8mk8m+FotFv10ulz/o8/m/XS6Xv+3gDkBdLpe/QIgBPV0ulz/t4A5AXS6XP0CIAT1dLpc/6PP5v10ulz/4+/0/XS6Xv+jz+b9dLpe/+Pv9PyaTyT6US9o/JpPJPhaLRb9dLpc/lEvaP10ulz8Wi0W/i8XiPyaTCcCLxeI/hlOAQIvF4r8mkwnAKZc0P8ZikUCLxeK/xmKRQIvF4r+GU4BAi8XivyaTCcAplzS/xmKRQIvF4j8mkwnAi8XiP8ZikUAmk8k+VCpVwCaTyb5UKlXA0bTCPtCvW8DRtMK+0K9bwKORrj6Iw2HAo5GuvojDYcDwiI6+cvtmwPCIjj5y+2bAJpNJPor8asAmk0m+ivxqwIOv0D3ugG3Ag6/Qve6AbcDxsKoOulxuwIvF4j+g4Mq/i8Xiv6Dgyr+LxeI/agjYv4vF4r9qCNi/i8Xiv+mZGMCLxeK/zS0fwIvF4j/pmRjAi8XiP80tH8Amk8k+VCpVwCaTyb5UKlXA0bTCPtCvW8DRtMK+0K9bwKORrj6Iw2HAo5GuvojDYcDwiI4+cvtmwPCIjr5y+2bAJpNJPor8asAmk0m+ivxqwIOv0D3ugG3Ag6/Qve6AbcAJafYNulxuwIvF4j/NLR/Ai8XiP+mZGMCLxeK/zS0fwIvF4r/pmRjAi8XiP0AVVsCLxeI/XIFPwIvF4r9AFVbAi8Xiv1yBT8CLxeK/QEXEPovF4j9ARcQ+i8Xiv2Dk+D6LxeI/YOT4PovF4r/4azW/i8XiP/hrNb+LxeK/aBwbv4vF4j9oHBu/i8Xiv0/HPMCLxeK/MltDwIvF4j9PxzzAi8XiPzJbQ8CLxeK/XIFPwIvF4r9AFVbAi8XiP1yBT8CLxeI/QBVWwIvF4r9qCNi/i8XiP2oI2L+LxeK/oODKv4vF4j+g4Mq/i8XiPzJbQ8CLxeI/T8c8wIvF4r8yW0PAi8Xiv0/HPMCLxeI/aBwbv4vF4r9oHBu/i8XiP/hrNb+LxeK/+Gs1v4vF4j9g5Pg+i8Xiv2Dk+D6LxeI/QEXEPovF4r9ARcQ+"),
|
||||||
|
"format": 34359742487,
|
||||||
|
"index_count": 18,
|
||||||
|
"index_data": PackedByteArray("VgBUAFUAVQBXAFYAVwBYAFYAWwBZAFoAWgBcAFsAXABdAFsA"),
|
||||||
|
"material": SubResource("StandardMaterial3D_fil5e"),
|
||||||
|
"name": "darkMetal",
|
||||||
|
"primitive": 3,
|
||||||
|
"uv_scale": Vector4(0, 0, 0, 0),
|
||||||
|
"vertex_count": 168,
|
||||||
|
"vertex_data": PackedByteArray("kML1vIaWnL3rUTg9kML1vOtRuL2wyJI8CtcjvIaWnL3rUTg9CtcjvOtRuL2wyJI8CtcjPIaWnL3rUTg9CtcjPOtRuL2wyJI8kML1PIaWnL3rUTg9kML1POtRuL2wyJI8kML1vOtRuL2wyJI8kML1vOtRuL3rUTi9CtcjvOtRuL2wyJI8CtcjvOtRuL3rUTi9CtcjPArXoz3rUTi9CtcjPArXoz3rUTg9kML1PArXoz3rUTi9kML1PArXoz3rUTg9kML1POtRuL3rUTi9CtcjPOtRuL3rUTi9kML1PArXoz3rUTi9CtcjPArXoz3rUTi9kML1vArXoz3rUTi9kML1vArXoz3rUTg9CtcjvArXoz3rUTi9CtcjvArXoz3rUTg9CtcjvOtRuL3rUTi9kML1vOtRuL3rUTi9CtcjvArXoz3rUTi9kML1vArXoz3rUTi9kML1vIaWnL3rUTg9CtcjvIaWnL3rUTg9kML1vArXoz3rUTg9CtcjvArXoz3rUTg9CtcjPIaWnL3rUTg9kML1PIaWnL3rUTg9CtcjPArXoz3rUTg9kML1PArXoz3rUTg9kML1vFyPwr2amZk9kML1vArXoz3rUTg9kML1vK1H4T2amZk9kML1vK1H4T2amZm9kML1vArXoz3rUTi9kML1vOtRuL3rUTi9kML1vIaWnL3rUTg9kML1vJDC9b3NzMw8kML1vOtRuL2wyJI8kML1vJDC9b2amZm9kML1PK1H4T2amZk9kML1PIaWnL3rUTg9kML1PFyPwr2amZk9kML1PJDC9b3NzMw8kML1POtRuL2wyJI8kML1PJDC9b2amZm9kML1POtRuL3rUTi9kML1PArXoz3rUTi9kML1PArXoz3rUTg9kML1PK1H4T2amZm9kML1PFyPwr2amZk9kML1vFyPwr2amZk9kML1PK1H4T2amZk9kML1vK1H4T2amZk9kML1vJDC9b2amZm9kML1PJDC9b2amZm9kML1vK1H4T2amZm9kML1PK1H4T2amZm9kML1vK1H4T2amZm9CtcjvK1H4T3rUTg9kML1vK1H4T2amZk9kML1PK1H4T2amZk9CtcjPK1H4T3rUTg9CtcjPK1H4T3rUTi9CtcjvK1H4T3rUTi9kML1PK1H4T2amZm9kML1vJDC9b3NzMw8kML1vFyPwr2amZk9kML1PJDC9b3NzMw8kML1PFyPwr2amZk9kML1vJDC9b2amZm9kML1vJDC9b3NzMw8kML1PJDC9b2amZm9kML1PJDC9b3NzMw8CtcjPOtRuL2wyJI8CtcjPOtRuL3rUTi9kML1POtRuL2wyJI8kML1POtRuL3rUTi9CtcjvArXoz3rUTg9CtcjvIaWnL3rUTg9CtcjvArXoz3rUTi9CtcjvOtRuL2wyJI8CtcjvOtRuL3rUTi9CtcjPIaWnL3rUTg9CtcjPArXoz3rUTg9CtcjPOtRuL2wyJI8CtcjPArXoz3rUTi9CtcjPOtRuL3rUTi9CtcjvK1H4T3rUTi9CtcjPK1H4T3rUTi93kEevKKU5j3rUTi93kEePKKU5j3rUTi9vOMNvB+F6z3rUTi9vOMNPB+F6z3rUTi9a7TnO/TC7z3rUTi9a7Tnu/TC7z3rUTi9CtejuyYE8z3rUTi9CtejOyYE8z3rUTi9oZ4pu+kP9T3rUTi9oZ4pO+kP9T3rUTi9AAAAAJDC9T3rUTi9a7Tnu/TC7z3rUTg9a7Tnu/TC7z3rUTi9CtejuyYE8z3rUTg9CtejuyYE8z3rUTi9vOMNPB+F6z3rUTg9a7TnO/TC7z3rUTg9vOMNPB+F6z3rUTi9a7TnO/TC7z3rUTi9CtcjPK1H4T3rUTg9CtcjvK1H4T3rUTg93kEePKKU5j3rUTg93kEevKKU5j3rUTg9vOMNPB+F6z3rUTg9vOMNvB+F6z3rUTg9a7TnO/TC7z3rUTg9a7Tnu/TC7z3rUTg9CtejOyYE8z3rUTg9CtejuyYE8z3rUTg9oZ4pO+kP9T3rUTg9oZ4pu+kP9T3rUTg9AAAAAJDC9T3rUTg9a7Tnu/TC7z3rUTg9vOMNvB+F6z3rUTg9a7Tnu/TC7z3rUTi9vOMNvB+F6z3rUTi93kEevKKU5j3rUTg9CtcjvK1H4T3rUTg93kEevKKU5j3rUTi9CtcjvK1H4T3rUTi9AAAAAJDC9T3rUTg9AAAAAJDC9T3rUTi9oZ4pO+kP9T3rUTg9oZ4pO+kP9T3rUTi9oZ4pO+kP9T3rUTg9oZ4pO+kP9T3rUTi9CtejOyYE8z3rUTg9CtejOyYE8z3rUTi93kEePKKU5j3rUTg9vOMNPB+F6z3rUTg93kEePKKU5j3rUTi9vOMNPB+F6z3rUTi9CtcjPK1H4T3rUTg93kEePKKU5j3rUTg9CtcjPK1H4T3rUTi93kEePKKU5j3rUTi9CtejOyYE8z3rUTg9CtejOyYE8z3rUTi9a7TnO/TC7z3rUTg9a7TnO/TC7z3rUTi9vOMNvB+F6z3rUTg93kEevKKU5j3rUTg9vOMNvB+F6z3rUTi93kEevKKU5j3rUTi9CtejuyYE8z3rUTg9CtejuyYE8z3rUTi9oZ4pu+kP9T3rUTg9oZ4pu+kP9T3rUTi9oZ4pu+kP9T3rUTg9oZ4pu+kP9T3rUTi9AAAAAJDC9T3rUTg9AAAAAJDC9T3rUTi9qar//wAAAICpqv//AAAAgKmq//8AAACAqar//wAAAICpqv//AAAAgKmq//8AAACAqar//wAAAICpqv//AAAAgP9///8AAACA/3///wAAAID/f///AAAAgP9///8AAACA/38AAAAAAID/fwAAAAAAgP9/AAAAAACA/38AAAAAAID/f/9/AAAAgP9//38AAACA/3//fwAAAID/f/9/AAAAgP9/AAAAAACA/38AAAAAAID/fwAAAAAAgP9/AAAAAACA/3//fwAAAID/f/9/AAAAgP9//38AAACA/3//fwAAAID/////AAAAgP////8AAACA/////wAAAID/////AAAAgP////8AAACA/////wAAAID/////AAAAgP////8AAACAAAD/fwAAAIAAAP9/AAAAgAAA/38AAACAAAD/fwAAAIAAAP9/AAAAgAAA/38AAACAAAD/fwAAAIAAAP9/AAAAgAAA/38AAACAAAD/fwAAAID///9/AAAAgP///38AAACA////fwAAAID///9/AAAAgP///38AAACA////fwAAAID///9/AAAAgP///38AAACA////fwAAAID///9/AAAAgP9//38AAACA/3//fwAAAID/f/9/AAAAgP9//38AAACA/////wAAAID/////AAAAgP////8AAACA/////wAAAID/f///AAAAgP9///8AAACA/3///wAAAID/f///AAAAgP9///8AAACA/3///wAAAID/f///AAAAgP9///8AAACA/3+qKgAAAID/f6oqAAAAgP9/qioAAACA/3+qKgAAAID/fwAAAAAAgP9/AAAAAACA/38AAAAAAID/fwAAAAAAgP9///8AAACA/3///wAAAID/f///AAAAgP9///8AAACAAAD/f/9//78AAP9//3//vwAA/3//f/+/AAD/f/9//78AAP9//3//v////3/+////////f/////////9//v///////3//////////f///////////AAAAgP////8AAACA/////wAAAID/////AAAAgP////8AAACA/////wAAAID/////AAAAgP////8AAACA/////wAAAID/////AAAAgP////8AAACA/////wAAAID/////AAAAgP8//78AAACA/z//vwAAAIAlUSXRAAAAgCVRJdEAAACAJdHZrgAAAID/v/+/AAAAgCXR2a4AAACA/7//vwAAAID/f/9/AAAAgP9//38AAACA/3//fwAAAID/f/9/AAAAgP9//38AAACA/3//fwAAAID/f/9/AAAAgP9//38AAACA/3//fwAAAID/f/9/AAAAgP9//38AAACA/3//fwAAAID/f/9/AAAAgP8//78AAACA2S7ZrgAAAID/P/+/AAAAgNku2a4AAACADBsMmwAAAIDkDuOOAAAAgAwbDJsAAACA5A7jjgAAAID/f///AAAAgP9///8AAACADJvy5AAAAIAMm/LkAAAAgAyb8uQAAACADJvy5AAAAIDZriXRAAAAgNmuJdEAAACA8uQMmwAAAIAl0dmuAAAAgPLkDJsAAACAJdHZrgAAAIAa8eOOAAAAgPLkDJsAAACAGvHjjgAAAIDy5AybAAAAgNmuJdEAAACA2a4l0QAAAID/v/+/AAAAgP+//78AAACA2S7ZrgAAAIAMGwybAAAAgNku2a4AAACADBsMmwAAAIAlUSXRAAAAgCVRJdEAAACA8mTy5AAAAIDyZPLkAAAAgPJk8uQAAACA8mTy5AAAAID/f///AAAAgP9///8AAACA")
|
||||||
|
}, {
|
||||||
|
"aabb": AABB(-0.03, -0.12, -0.075, 0.06, 0.24, 0.15),
|
||||||
|
"attribute_data": PackedByteArray("XS6XP0T3Qj9dLpc/dxH6PyaTyT5E90I/JpPJPncR+j8mk8m+RPdCPyaTyb53Efo/XS6Xv0T3Qj9dLpe/dxH6P10ul7+US9o/XS6XvxaLRb8mk8m+lEvaPyaTyb4Wi0W/JpPJvhaLRb8mk8m+xmIxQF0ul78Wi0W/XS6Xv8ZiMUBdLpc/xmKRQCaTyT7GYpFAXS6XPyaTCcAmk8k+JpMJwF0ulz8Wi0W/XS6XP8ZiMUAmk8k+FotFvyaTyT7GYjFAJpPJvsZikUBdLpe/xmKRQCaTyb4mkwnAXS6XvyaTCcBdLpc/hlOAQCaTyT6GU4BAXS6XPyaTCcAmk8k+JpMJwCaTyb6GU4BAXS6Xv4ZTgEAmk8m+JpMJwF0ul78mkwnA9Pk8QF6vl0CLxeI/JpMJwPT5PEBUKlXA9Pk8wFQqVcCLxeK/JpMJwIvF4r/GYpFAi8XiP4ZTgEDw93s/XS63QCmXND/GYpFA9Pk8wF0ut0D0+TzAVCpVwIvF4r+GU4BA9Pk8wF6vl0Dw93u/XS63QCmXNL/GYpFA9Pk8QF0ut0CLxeI/xmKRQIvF4j8mkwnAi8XivyaTCcD0+TxAVCpVwF0ulz9er5dAXS6Xv16vl0BdLpc/VCpVwF0ul79UKlXAXS6XP10ut0BdLpe/XS63QF0ulz9UKlXAXS6Xv1QqVcBdLpe/6PP5vyaTyb7GYjFAXS6Xv/T5fEBdLpc/9Pl8QCaTyT7GYjFAJpPJPhaLRb8mk8m+FotFv10ulz/o8/m/XS6Xv+3gDkBdLpe/QIgBPV0ulz/t4A5AXS6XP0CIAT1dLpc/6PP5v10ulz/4+/0/XS6Xv+jz+b9dLpe/+Pv9PyaTyT6US9o/JpPJPhaLRb9dLpc/lEvaP10ulz8Wi0W/i8XiPyaTCcCLxeI/hlOAQIvF4r8mkwnAKZc0P8ZikUCLxeK/xmKRQIvF4r+GU4BAi8XivyaTCcAplzS/xmKRQIvF4j8mkwnAi8XiP8ZikUAmk8k+VCpVwCaTyb5UKlXA0bTCPtCvW8DRtMK+0K9bwKORrj6Iw2HAo5GuvojDYcDwiI6+cvtmwPCIjj5y+2bAJpNJPor8asAmk0m+ivxqwIOv0D3ugG3Ag6/Qve6AbcDxsKoOulxuwIvF4j+g4Mq/i8Xiv6Dgyr+LxeI/agjYv4vF4r9qCNi/i8Xiv+mZGMCLxeK/zS0fwIvF4j/pmRjAi8XiP80tH8Amk8k+VCpVwCaTyb5UKlXA0bTCPtCvW8DRtMK+0K9bwKORrj6Iw2HAo5GuvojDYcDwiI4+cvtmwPCIjr5y+2bAJpNJPor8asAmk0m+ivxqwIOv0D3ugG3Ag6/Qve6AbcAJafYNulxuwIvF4j/NLR/Ai8XiP+mZGMCLxeK/zS0fwIvF4r/pmRjAi8XiP0AVVsCLxeI/XIFPwIvF4r9AFVbAi8Xiv1yBT8CLxeK/QEXEPovF4j9ARcQ+i8Xiv2Dk+D6LxeI/YOT4PovF4r/4azW/i8XiP/hrNb+LxeK/aBwbv4vF4j9oHBu/i8Xiv0/HPMCLxeK/MltDwIvF4j9PxzzAi8XiPzJbQ8CLxeK/XIFPwIvF4r9AFVbAi8XiP1yBT8CLxeI/QBVWwIvF4r9qCNi/i8XiP2oI2L+LxeK/oODKv4vF4j+g4Mq/i8XiPzJbQ8CLxeI/T8c8wIvF4r8yW0PAi8Xiv0/HPMCLxeI/aBwbv4vF4r9oHBu/i8XiP/hrNb+LxeK/+Gs1v4vF4j9g5Pg+i8Xiv2Dk+D6LxeI/QEXEPovF4r9ARcQ+"),
|
||||||
|
"format": 34359742487,
|
||||||
|
"index_count": 138,
|
||||||
|
"index_data": PackedByteArray("YABeAF8AXwBhAGAAYQBiAGAAYQBjAGIAYwBkAGIAZABlAGIAZABmAGUAZABnAGYAZwBoAGYAZwBpAGgAaQBqAGgAbQBrAGwAbABuAG0AcQBvAHAAcAByAHEAdQBzAHQAdAB2AHUAdgB3AHUAdgB4AHcAeAB5AHcAeAB6AHkAegB7AHkAegB8AHsAfAB9AHsAfAB+AH0AfgB/AH0AggCAAIEAgQCDAIIAhgCEAIUAhQCHAIYAigCIAIkAiQCLAIoAjgCMAI0AjQCPAI4AkgCQAJEAkQCTAJIAlgCUAJUAlQCXAJYAmgCYAJkAmQCbAJoAngCcAJ0AnQCfAJ4AogCgAKEAoQCjAKIApgCkAKUApQCnAKYA"),
|
||||||
|
"material": SubResource("StandardMaterial3D_bfdxb"),
|
||||||
|
"name": "yellow",
|
||||||
|
"primitive": 3,
|
||||||
|
"uv_scale": Vector4(0, 0, 0, 0),
|
||||||
|
"vertex_count": 168,
|
||||||
|
"vertex_data": PackedByteArray("kML1vIaWnL3rUTg9kML1vOtRuL2wyJI8CtcjvIaWnL3rUTg9CtcjvOtRuL2wyJI8CtcjPIaWnL3rUTg9CtcjPOtRuL2wyJI8kML1PIaWnL3rUTg9kML1POtRuL2wyJI8kML1vOtRuL2wyJI8kML1vOtRuL3rUTi9CtcjvOtRuL2wyJI8CtcjvOtRuL3rUTi9CtcjPArXoz3rUTi9CtcjPArXoz3rUTg9kML1PArXoz3rUTi9kML1PArXoz3rUTg9kML1POtRuL3rUTi9CtcjPOtRuL3rUTi9kML1PArXoz3rUTi9CtcjPArXoz3rUTi9kML1vArXoz3rUTi9kML1vArXoz3rUTg9CtcjvArXoz3rUTi9CtcjvArXoz3rUTg9CtcjvOtRuL3rUTi9kML1vOtRuL3rUTi9CtcjvArXoz3rUTi9kML1vArXoz3rUTi9kML1vIaWnL3rUTg9CtcjvIaWnL3rUTg9kML1vArXoz3rUTg9CtcjvArXoz3rUTg9CtcjPIaWnL3rUTg9kML1PIaWnL3rUTg9CtcjPArXoz3rUTg9kML1PArXoz3rUTg9kML1vFyPwr2amZk9kML1vArXoz3rUTg9kML1vK1H4T2amZk9kML1vK1H4T2amZm9kML1vArXoz3rUTi9kML1vOtRuL3rUTi9kML1vIaWnL3rUTg9kML1vJDC9b3NzMw8kML1vOtRuL2wyJI8kML1vJDC9b2amZm9kML1PK1H4T2amZk9kML1PIaWnL3rUTg9kML1PFyPwr2amZk9kML1PJDC9b3NzMw8kML1POtRuL2wyJI8kML1PJDC9b2amZm9kML1POtRuL3rUTi9kML1PArXoz3rUTi9kML1PArXoz3rUTg9kML1PK1H4T2amZm9kML1PFyPwr2amZk9kML1vFyPwr2amZk9kML1PK1H4T2amZk9kML1vK1H4T2amZk9kML1vJDC9b2amZm9kML1PJDC9b2amZm9kML1vK1H4T2amZm9kML1PK1H4T2amZm9kML1vK1H4T2amZm9CtcjvK1H4T3rUTg9kML1vK1H4T2amZk9kML1PK1H4T2amZk9CtcjPK1H4T3rUTg9CtcjPK1H4T3rUTi9CtcjvK1H4T3rUTi9kML1PK1H4T2amZm9kML1vJDC9b3NzMw8kML1vFyPwr2amZk9kML1PJDC9b3NzMw8kML1PFyPwr2amZk9kML1vJDC9b2amZm9kML1vJDC9b3NzMw8kML1PJDC9b2amZm9kML1PJDC9b3NzMw8CtcjPOtRuL2wyJI8CtcjPOtRuL3rUTi9kML1POtRuL2wyJI8kML1POtRuL3rUTi9CtcjvArXoz3rUTg9CtcjvIaWnL3rUTg9CtcjvArXoz3rUTi9CtcjvOtRuL2wyJI8CtcjvOtRuL3rUTi9CtcjPIaWnL3rUTg9CtcjPArXoz3rUTg9CtcjPOtRuL2wyJI8CtcjPArXoz3rUTi9CtcjPOtRuL3rUTi9CtcjvK1H4T3rUTi9CtcjPK1H4T3rUTi93kEevKKU5j3rUTi93kEePKKU5j3rUTi9vOMNvB+F6z3rUTi9vOMNPB+F6z3rUTi9a7TnO/TC7z3rUTi9a7Tnu/TC7z3rUTi9CtejuyYE8z3rUTi9CtejOyYE8z3rUTi9oZ4pu+kP9T3rUTi9oZ4pO+kP9T3rUTi9AAAAAJDC9T3rUTi9a7Tnu/TC7z3rUTg9a7Tnu/TC7z3rUTi9CtejuyYE8z3rUTg9CtejuyYE8z3rUTi9vOMNPB+F6z3rUTg9a7TnO/TC7z3rUTg9vOMNPB+F6z3rUTi9a7TnO/TC7z3rUTi9CtcjPK1H4T3rUTg9CtcjvK1H4T3rUTg93kEePKKU5j3rUTg93kEevKKU5j3rUTg9vOMNPB+F6z3rUTg9vOMNvB+F6z3rUTg9a7TnO/TC7z3rUTg9a7Tnu/TC7z3rUTg9CtejOyYE8z3rUTg9CtejuyYE8z3rUTg9oZ4pO+kP9T3rUTg9oZ4pu+kP9T3rUTg9AAAAAJDC9T3rUTg9a7Tnu/TC7z3rUTg9vOMNvB+F6z3rUTg9a7Tnu/TC7z3rUTi9vOMNvB+F6z3rUTi93kEevKKU5j3rUTg9CtcjvK1H4T3rUTg93kEevKKU5j3rUTi9CtcjvK1H4T3rUTi9AAAAAJDC9T3rUTg9AAAAAJDC9T3rUTi9oZ4pO+kP9T3rUTg9oZ4pO+kP9T3rUTi9oZ4pO+kP9T3rUTg9oZ4pO+kP9T3rUTi9CtejOyYE8z3rUTg9CtejOyYE8z3rUTi93kEePKKU5j3rUTg9vOMNPB+F6z3rUTg93kEePKKU5j3rUTi9vOMNPB+F6z3rUTi9CtcjPK1H4T3rUTg93kEePKKU5j3rUTg9CtcjPK1H4T3rUTi93kEePKKU5j3rUTi9CtejOyYE8z3rUTg9CtejOyYE8z3rUTi9a7TnO/TC7z3rUTg9a7TnO/TC7z3rUTi9vOMNvB+F6z3rUTg93kEevKKU5j3rUTg9vOMNvB+F6z3rUTi93kEevKKU5j3rUTi9CtejuyYE8z3rUTg9CtejuyYE8z3rUTi9oZ4pu+kP9T3rUTg9oZ4pu+kP9T3rUTi9oZ4pu+kP9T3rUTg9oZ4pu+kP9T3rUTi9AAAAAJDC9T3rUTg9AAAAAJDC9T3rUTi9qar//wAAAICpqv//AAAAgKmq//8AAACAqar//wAAAICpqv//AAAAgKmq//8AAACAqar//wAAAICpqv//AAAAgP9///8AAACA/3///wAAAID/f///AAAAgP9///8AAACA/38AAAAAAID/fwAAAAAAgP9/AAAAAACA/38AAAAAAID/f/9/AAAAgP9//38AAACA/3//fwAAAID/f/9/AAAAgP9/AAAAAACA/38AAAAAAID/fwAAAAAAgP9/AAAAAACA/3//fwAAAID/f/9/AAAAgP9//38AAACA/3//fwAAAID/////AAAAgP////8AAACA/////wAAAID/////AAAAgP////8AAACA/////wAAAID/////AAAAgP////8AAACAAAD/fwAAAIAAAP9/AAAAgAAA/38AAACAAAD/fwAAAIAAAP9/AAAAgAAA/38AAACAAAD/fwAAAIAAAP9/AAAAgAAA/38AAACAAAD/fwAAAID///9/AAAAgP///38AAACA////fwAAAID///9/AAAAgP///38AAACA////fwAAAID///9/AAAAgP///38AAACA////fwAAAID///9/AAAAgP9//38AAACA/3//fwAAAID/f/9/AAAAgP9//38AAACA/////wAAAID/////AAAAgP////8AAACA/////wAAAID/f///AAAAgP9///8AAACA/3///wAAAID/f///AAAAgP9///8AAACA/3///wAAAID/f///AAAAgP9///8AAACA/3+qKgAAAID/f6oqAAAAgP9/qioAAACA/3+qKgAAAID/fwAAAAAAgP9/AAAAAACA/38AAAAAAID/fwAAAAAAgP9///8AAACA/3///wAAAID/f///AAAAgP9///8AAACAAAD/fwAAAIAAAP9/AAAAgAAA/38AAACAAAD/fwAAAIAAAP9/AAAAgP///38AAACA////fwAAAID///9/AAAAgP///38AAACA////fwAAAID/////AAD/v/////8AAP+//////wAA/7//////AAD/v/////8AAP+//////wAA/7//////AAD/v/////8AAP+//////wAA/7//////AAD/v/////8AAP+//////wAA/7//////AAD/v/8//7//f/+//z//v/9//78lUSXR/3//vyVRJdH/f/+/JdHZrv//////v/+//////yXR2a7//////7//v///////f/9/////v/9//3////+//3//f////7//f/9/////v/9//3////+//3//f////7//f/9/////v/9//3////+//3//f////7//f/9/////v/9//3////+//3//f////7//f/9/////v/8//7//f/+/2S7Zrv9//7//P/+//3//v9ku2a7/f/+/DBsMm/9//7/kDuOO/3//vwwbDJv/f/+/5A7jjv9//7//f/////////9/////////DJvy5P////8Mm/Lk/////wyb8uT/////DJvy5P/////ZriXR/////9muJdH/////8uQMm/////8l0dmu//////LkDJv/////JdHZrv////8a8eOO//////LkDJv/////GvHjjv/////y5Ayb/////9muJdH/////2a4l0f//////v/+///////+//7//////2S7Zrv9//78MGwyb/3//v9ku2a7/f/+/DBsMm/9//78lUSXR/3//vyVRJdH/f/+/8mTy5P9//7/yZPLk/3//v/Jk8uT/f/+/8mTy5P9//7//f////3//v/9/////f/+/")
|
||||||
|
}]
|
||||||
|
blend_shape_mode = 0
|
||||||
|
shadow_mesh = SubResource("ArrayMesh_j3k8o")
|
||||||
|
|
||||||
|
[sub_resource type="BoxShape3D" id="BoxShape3D_y1cnp"]
|
||||||
|
size = Vector3(0.0599088, 0.407185, 0.143523)
|
||||||
|
|
||||||
|
[node name="blasterI_Clip" type="RigidBody3D"]
|
||||||
|
collision_layer = 8
|
||||||
|
collision_mask = 5
|
||||||
|
script = ExtResource("1_6xwda")
|
||||||
|
weapon = SubResource("Resource_yxf5f")
|
||||||
|
TYPE = "Ammo"
|
||||||
|
|
||||||
|
[node name="clipA2" type="MeshInstance3D" parent="."]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1.936, 0, 0, 0, 0.99, 0, 0, 0)
|
||||||
|
mesh = SubResource("ArrayMesh_py3xv")
|
||||||
|
skeleton = NodePath("")
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
|
||||||
|
shape = SubResource("BoxShape3D_y1cnp")
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
[gd_scene load_steps=11 format=4 uid="uid://cgt2lt4ultlaq"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://deaf6cmuofa0" path="res://client/template/scripts/Weapon_State_Machine/PickUp Weapons/Weapon_Pick_Up.gd" id="1_qqhy0"]
|
||||||
|
[ext_resource type="Script" uid="uid://bw4j1fbww4k8s" path="res://client/template/scripts/Weapon_State_Machine/WeaponSlot.gd" id="2_ybq5e"]
|
||||||
|
[ext_resource type="Resource" uid="uid://cd8msvjysh2uv" path="res://client/template/scripts/Weapon_State_Machine/Weapon_Resources/blasterM.tres" id="3_parqs"]
|
||||||
|
|
||||||
|
[sub_resource type="Resource" id="Resource_jnsso"]
|
||||||
|
resource_local_to_scene = true
|
||||||
|
script = ExtResource("2_ybq5e")
|
||||||
|
weapon = ExtResource("3_parqs")
|
||||||
|
current_ammo = 9
|
||||||
|
reserve_ammo = 0
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_0eh6a"]
|
||||||
|
resource_name = "metal"
|
||||||
|
albedo_color = Color(1, 0.894118, 0.505882, 1)
|
||||||
|
metallic = 1.0
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_8qvhc"]
|
||||||
|
resource_name = "darkMetal"
|
||||||
|
albedo_color = Color(0.793075, 0.81829, 0.89044, 1)
|
||||||
|
metallic = 1.0
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_mihsn"]
|
||||||
|
resource_name = "yellow"
|
||||||
|
albedo_color = Color(0.998274, 0.894448, 0.505969, 1)
|
||||||
|
metallic = 1.0
|
||||||
|
|
||||||
|
[sub_resource type="ArrayMesh" id="ArrayMesh_68l5q"]
|
||||||
|
_surfaces = [{
|
||||||
|
"aabb": AABB(-0.03, -0.12, -0.075, 0.06, 0.24, 0.15),
|
||||||
|
"format": 34896613377,
|
||||||
|
"index_count": 168,
|
||||||
|
"index_data": PackedByteArray("AgAAAAEAAQADAAIABgAEAAUABQAHAAYAAwABAAgACAAJAAMADAAKAAsACwANAAwADAAOAA8ADwAKAAwAEgAQABEAEQATABIAEgAJAAgACAAQABIAEQAAAAIAAgATABEACwAEAAYABgANAAsAFQAUABEAEQAWABUAEQAQABYAEAAIABYAAAARABQAFAAXAAAAFwABAAAAFwAYAAEAGAAIAAEAGAAWAAgAGgAZAAYABgAbABoABgAHABsABwAcABsABwAOABwADgAMABwADQAGABkAGQAdAA0AHQAMAA0AHQAcAAwAGQAaABQAFAAVABkAFgAYABwAHAAdABYAFQAWAB4AHgAZABUAHgAfABkAHwAgABkAIQAeABYAFgAdACEAHQAgACEAHQAZACAAGwAXABQAFAAaABsAHAAYABcAFwAbABwABwAFAA8ADwAOAAcA"),
|
||||||
|
"name": "metal",
|
||||||
|
"primitive": 3,
|
||||||
|
"uv_scale": Vector4(0, 0, 0, 0),
|
||||||
|
"vertex_count": 56,
|
||||||
|
"vertex_data": PackedByteArray("AABxLszMAAAAAP8fk54AAFVVcS7MzAAAVVX/H5OeAACpqnEuzMwAAKmq/x+TngAA//9xLszMAAD///8fk54AAAAA/x8zMwAAVVX/HzMzAACpqlTVMzMAAKmqVNXMzAAA//9U1TMzAAD//1TVzMwAAP///x8zMwAAqar/HzMzAAAAAFTVMzMAAAAAVNXMzAAAVVVU1TMzAABVVVTVzMwAAAAAqhr//wAAAABU9f//AAAAAFT1AAAAAAAAAACpqgAAAAAAAAAAAAD//1T1//8AAP//qhr//wAA//8AAKmqAAD//wAAAAAAAP//VPUAAAAAVVVU9czMAACpqlT1zMwAAKmqVPUzMwAAVVVU9TMzAADJVhf4MzMAADWpF/gzMwAADFup+jMzAADypKn6MzMAACqe3/wzMwAA1GHf/DMzAACqapH+MzMAAFSVkf4zMwAA9HSh/zMzAAAKi6H/MzMAAP9///8zMwAA1GHf/MzMAACqapH+zMwAAPKkqfrMzAAAKp7f/MzMAAA1qRf4zMwAAMlWF/jMzAAADFup+szMAABUlZH+zMwAAAqLof/MzAAA9HSh/8zMAAD/f///zMwAAA==")
|
||||||
|
}, {
|
||||||
|
"aabb": AABB(-0.03, -0.12, -0.075, 0.06, 0.24, 0.15),
|
||||||
|
"format": 34896613377,
|
||||||
|
"index_count": 18,
|
||||||
|
"index_data": PackedByteArray("EgATAAIAAgADABIAAwAJABIABQAEAAsACwAKAAUACgAPAAUA"),
|
||||||
|
"name": "darkMetal",
|
||||||
|
"primitive": 3,
|
||||||
|
"uv_scale": Vector4(0, 0, 0, 0),
|
||||||
|
"vertex_count": 56,
|
||||||
|
"vertex_data": PackedByteArray("AABxLszMAAAAAP8fk54AAFVVcS7MzAAAVVX/H5OeAACpqnEuzMwAAKmq/x+TngAA//9xLszMAAD///8fk54AAAAA/x8zMwAAVVX/HzMzAACpqlTVMzMAAKmqVNXMzAAA//9U1TMzAAD//1TVzMwAAP///x8zMwAAqar/HzMzAAAAAFTVMzMAAAAAVNXMzAAAVVVU1TMzAABVVVTVzMwAAAAAqhr//wAAAABU9f//AAAAAFT1AAAAAAAAAACpqgAAAAAAAAAAAAD//1T1//8AAP//qhr//wAA//8AAKmqAAD//wAAAAAAAP//VPUAAAAAVVVU9czMAACpqlT1zMwAAKmqVPUzMwAAVVVU9TMzAADJVhf4MzMAADWpF/gzMwAADFup+jMzAADypKn6MzMAACqe3/wzMwAA1GHf/DMzAACqapH+MzMAAFSVkf4zMwAA9HSh/zMzAAAKi6H/MzMAAP9///8zMwAA1GHf/MzMAACqapH+zMwAAPKkqfrMzAAAKp7f/MzMAAA1qRf4zMwAAMlWF/jMzAAADFup+szMAABUlZH+zMwAAAqLof/MzAAA9HSh/8zMAAD/f///zMwAAA==")
|
||||||
|
}, {
|
||||||
|
"aabb": AABB(-0.03, -0.12, -0.075, 0.06, 0.24, 0.15),
|
||||||
|
"format": 34896613377,
|
||||||
|
"index_count": 138,
|
||||||
|
"index_data": PackedByteArray("IgAhACAAIAAjACIAIwAkACIAIwAlACQAJQAmACQAJgAnACQAJgAoACcAJgApACgAKQAqACgAKQArACoAKwAsACoALgAtACcAJwAoAC4AJQAvADAAMAAmACUAMQAfAB4AHgAyADEAMgAvADEAMgAzAC8AMwAwAC8AMwAtADAALQA0ADAALQAuADQALgA1ADQALgA2ADUANgA3ADUAJwAtADMAMwAkACcAIgAyAB4AHgAhACIANQA3ACwALAArADUANAA1ACsAKwApADQAIwAxAC8ALwAlACMAIAAfADEAMQAjACAAMAA0ACkAKQAmADAAJAAzADIAMgAiACQANgAuACgAKAAqADYANwA2ACoAKgAsADcA"),
|
||||||
|
"name": "yellow",
|
||||||
|
"primitive": 3,
|
||||||
|
"uv_scale": Vector4(0, 0, 0, 0),
|
||||||
|
"vertex_count": 56,
|
||||||
|
"vertex_data": PackedByteArray("AABxLszMAAAAAP8fk54AAFVVcS7MzAAAVVX/H5OeAACpqnEuzMwAAKmq/x+TngAA//9xLszMAAD///8fk54AAAAA/x8zMwAAVVX/HzMzAACpqlTVMzMAAKmqVNXMzAAA//9U1TMzAAD//1TVzMwAAP///x8zMwAAqar/HzMzAAAAAFTVMzMAAAAAVNXMzAAAVVVU1TMzAABVVVTVzMwAAAAAqhr//wAAAABU9f//AAAAAFT1AAAAAAAAAACpqgAAAAAAAAAAAAD//1T1//8AAP//qhr//wAA//8AAKmqAAD//wAAAAAAAP//VPUAAAAAVVVU9czMAACpqlT1zMwAAKmqVPUzMwAAVVVU9TMzAADJVhf4MzMAADWpF/gzMwAADFup+jMzAADypKn6MzMAACqe3/wzMwAA1GHf/DMzAACqapH+MzMAAFSVkf4zMwAA9HSh/zMzAAAKi6H/MzMAAP9///8zMwAA1GHf/MzMAACqapH+zMwAAPKkqfrMzAAAKp7f/MzMAAA1qRf4zMwAAMlWF/jMzAAADFup+szMAABUlZH+zMwAAAqLof/MzAAA9HSh/8zMAAD/f///zMwAAA==")
|
||||||
|
}]
|
||||||
|
blend_shape_mode = 0
|
||||||
|
|
||||||
|
[sub_resource type="ArrayMesh" id="ArrayMesh_5ckjg"]
|
||||||
|
resource_name = "clipA_Mesh clipA"
|
||||||
|
_surfaces = [{
|
||||||
|
"aabb": AABB(-0.03, -0.12, -0.075, 0.06, 0.24, 0.15),
|
||||||
|
"attribute_data": PackedByteArray("MrMGkTKzrqsQkQaREJGuq+5uBpHubq6rzEwGkcxMrqvMTCGmzEy+bu5uIabubr5u7m6+bu5u+L3MTL5uzEz4vTKzluUQkZblMrPuTxCR7k8ys75uMrP4vRCRvm4Qkfi97m6W5cxMluXubu5PzEzuTzKzqtkQkarZMrPuTxCR7k/ubqrZzEyq2e5u7k/MTO5P///86cvM7k///4U1AACFNTMz7k8zM5bly8yq2aqq//+TnpblAAD//wAAhTUzM6rZAAD86VRV//9rYZbl/////8vMluXLzO5PMzPuT///hTUys/zpzEz86TKzhTXMTIU1MrP//8xM//8ys4U1zEyFNcxMVVTubvi9zExh2DKzYdgQkfi9EJG+bu5uvm4ys1VUzEzqscxMtIAys+qxMrO0gDKzVVQys12szExVVMxMXawQkSGmEJG+bjKzIaYys75uy8zuT8vMqtkzM+5Pk56W5TMzluUzM6rZMzPuT2thluXLzO5Py8yW5RCRhTXuboU1e5A+M4NvPjPHjh8xN3EfMe5zTC8QjEwvh4jmLXd35i1qhAUtlHsFLf9/uCzLzI5cMzOOXMvMQlozM0JaMzOuSjMzYkjLzK5Ky8xiSBCRhTXuboU1e5A+M4NvPjPHjh8xN3EfMRCMTC/uc0wvh4jmLXd35i1qhAUtlHsFLf9/uCzLzGJIy8yuSjMzYkgzM65Ky8wzNcvMgDczMzM1MzOANzMzkYjLzJGIMzPeisvM3oozMyZwy8wmcDMzc3LLzHNyMzMLPjMzvjvLzAs+y8y+OzMzgDczMzM1y8yAN8vMMzUzM0Jay8xCWjMzjlzLzI5cy8y+O8vMCz4zM747MzMLPsvMc3IzM3Nyy8wmcDMzJnDLzN6KMzPeisvMkYgzM5GI"),
|
||||||
|
"format": 34896613399,
|
||||||
|
"index_count": 168,
|
||||||
|
"index_data": PackedByteArray("AgAAAAEAAQADAAIABgAEAAUABQAHAAYACgAIAAkACQALAAoADgAMAA0ADQAPAA4AEgAQABEAEQATABIAFgAUABUAFQAXABYAGgAYABkAGQAbABoAHgAcAB0AHQAfAB4AIgAgACEAIQAjACIAJgAkACUAJQAnACYAJQAoACcAKAApACcAKgAlACQAJAArACoAKwAsACoAKwAtACwALQApACwALQAnACkAMAAuAC8ALwAxADAALwAyADEAMgAzADEAMgA0ADMANAA1ADMANgAvAC4ALgA3ADYANwA1ADYANwAzADUAOgA4ADkAOQA7ADoAPgA8AD0APQA/AD4AQgBAAEEAQQBDAEIAQQBEAEMARABFAEMARgBBAEAAQABHAEYARwBFAEYARwBDAEUASgBIAEkASQBLAEoATgBMAE0ATQBPAE4AUgBQAFEAUQBTAFIA"),
|
||||||
|
"material": SubResource("StandardMaterial3D_0eh6a"),
|
||||||
|
"name": "metal",
|
||||||
|
"primitive": 3,
|
||||||
|
"uv_scale": Vector4(5.90551, 11.4488, 0, 0),
|
||||||
|
"vertex_count": 168,
|
||||||
|
"vertex_data": PackedByteArray("AABxLszM//8AAP8fk57//1VVcS7MzP//VVX/H5Oe//+pqnEuzMz//6mq/x+Tnv////9xLszM//////8fk57//wAA/x+Tnv+/AAD/HzMz/79VVf8fk57/v1VV/x8zM/+/qapU1TMz//+pqlTVzMz/////VNUzM/////9U1czM//////8fMzP/f6mq/x8zM/9///9U1TMz/3+pqlTVMzP/fwAAVNUzM///AABU1czM//9VVVTVMzP//1VVVNXMzP//VVX/HzMz/38AAP8fMzP/f1VVVNUzM/9/AABU1TMz/38AAHEuzMz//1VVcS7MzP//AABU1czM//9VVVTVzMz//6mqcS7MzP////9xLszM//+pqlTVzMz/////VNXMzP//AACqGv///78AAFTVzMz/vwAAVPX///+/AABU9QAA/78AAFTVMzP/vwAA/x8zM/+/AABxLszM/78AAAAAqar/vwAA/x+Tnv+/AAAAAAAA/7///1T1////v///cS7MzP+///+qGv///7///wAAqar/v////x+Tnv+///8AAAAA/7////8fMzP/v///VNUzM/+///9U1czM/7///1T1AAD/v///qhr///9/AACqGv///3///1T1////fwAAVPX///9/AAAAAAAA/////wAAAAD//wAAVPUAAP////9U9QAA//8AAFT1AAD/v1VVVPXMzP+/AABU9f///7///1T1////v6mqVPXMzP+/qapU9TMz/79VVVT1MzP/v///VPUAAP+/AAAAAKmqG60AAKoa//8brf//AACpqhut//+qGv//G60AAAAAAAD//wAAAACpqv////8AAAAA/////wAAqar//6mq/x+Tnv+/qar/HzMz/7////8fk57/v////x8zM/+/VVVU1czMVNVVVXEuzMxU1VVVVNUzM1TVVVX/H5OeVNVVVf8fMzNU1amqcS7MzFTVqapU1czMVNWpqv8fk55U1amqVNUzM1TVqar/HzMzVNVVVVT1MzP//6mqVPUzM///yVYX+DMz//81qRf4MzP//wxbqfozM///8qSp+jMz//8qnt/8MzP//9Rh3/wzM///qmqR/jMz//9UlZH+MzP///R0of8zM///Couh/zMz////f///MzP//9Rh3/zMzFTV1GHf/DMzVNWqapH+zMxU1apqkf4zM1TV8qSp+szMVNUqnt/8zMxU1fKkqfozM1TVKp7f/DMzVNWpqlT1zMz//1VVVPXMzP//NakX+MzM///JVhf4zMz///KkqfrMzP//DFup+szM//8qnt/8zMz//9Rh3/zMzP//VJWR/szM//+qapH+zMz//wqLof/MzP//9HSh/8zM////f///zMz//9Rh3/zMzFTVDFup+szMVNXUYd/8MzNU1QxbqfozM1TVyVYX+MzMVNVVVVT1zMxU1clWF/gzM1TVVVVU9TMzVNX/f///zMxU1f9///8zM1TVCouh/8zMVNUKi6H/MzNU1QqLof/MzFTVCouh/zMzVNVUlZH+zMxU1VSVkf4zM1TVNakX+MzMVNXypKn6zMxU1TWpF/gzM1TV8qSp+jMzVNWpqlT1zMxU1TWpF/jMzFTVqapU9TMzVNU1qRf4MzNU1VSVkf7MzFTVVJWR/jMzVNUqnt/8zMxU1Sqe3/wzM1TVDFup+szMVNXJVhf4zMxU1QxbqfozM1TVyVYX+DMzVNWqapH+zMxU1apqkf4zM1TV9HSh/8zMVNX0dKH/MzNU1fR0of/MzFTV9HSh/zMzVNX/f///zMxU1f9///8zM1TV/38az/9/Gs//fxrP/38az/9/Gs//fxrP/38az/9/Gs////9/////f////3////9//3//P/9//z//f/8//3//P/9/////f////3////9/////f/8//3//P/9//z//f/8//3////9/////f////3////9/////f////3////9/////f////3////9/////f////3/+//9/////f////3////9/////f/7//3/+//9//v//f/7//3/+//9/AAD/fwAA/38AAP9/AAD/fwAA/38AAP9/AAD/fwAA/38AAP9/AAD/f////3////9/////f////3////9/////f////3///////3/+//9/////f////3/+//9/////f/7//3////9/AAD/fwAA/38AAP9/AAD/f/9//z//f/8//3//P/9//z////9/////f////3////9//3////9/////f////3////9/////fwAA/38AAP9/AAD/fwAA/38AAP9/////f////3////9/////f////3////9/////f////3////9/////f////3////9/////v/+//7//vyXR2a4l0dmu2a7ZLv+//z/Zrtku/7//P/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//v/+/2a4l0f+//7/ZriXRDJvy5OOOGvEMm/Lk444a8f///3////9/8uTyZPLk8mTy5PJk8uTyZCXRJVEl0SVRDJsMG9mu2S4Mmwwb2a7ZLuOO5A4Mmwwb447kDgybDBsl0SVRJdElUf+//z//v/8/2a4l0Qyb8uTZriXRDJvy5CXR2a4l0dmu8uQMm/LkDJvy5Ayb8uQMm////3////9/")
|
||||||
|
}, {
|
||||||
|
"aabb": AABB(-0.03, -0.12, -0.075, 0.06, 0.24, 0.15),
|
||||||
|
"attribute_data": PackedByteArray("MrMGkTKzrqsQkQaREJGuq+5uBpHubq6rzEwGkcxMrqvMTCGmzEy+bu5uIabubr5u7m6+bu5u+L3MTL5uzEz4vTKzluUQkZblMrPuTxCR7k8ys75uMrP4vRCRvm4Qkfi97m6W5cxMluXubu5PzEzuTzKzqtkQkarZMrPuTxCR7k/ubqrZzEyq2e5u7k/MTO5P///86cvM7k///4U1AACFNTMz7k8zM5bly8yq2aqq//+TnpblAAD//wAAhTUzM6rZAAD86VRV//9rYZbl/////8vMluXLzO5PMzPuT///hTUys/zpzEz86TKzhTXMTIU1MrP//8xM//8ys4U1zEyFNcxMVVTubvi9zExh2DKzYdgQkfi9EJG+bu5uvm4ys1VUzEzqscxMtIAys+qxMrO0gDKzVVQys12szExVVMxMXawQkSGmEJG+bjKzIaYys75uy8zuT8vMqtkzM+5Pk56W5TMzluUzM6rZMzPuT2thluXLzO5Py8yW5RCRhTXuboU1e5A+M4NvPjPHjh8xN3EfMe5zTC8QjEwvh4jmLXd35i1qhAUtlHsFLf9/uCzLzI5cMzOOXMvMQlozM0JaMzOuSjMzYkjLzK5Ky8xiSBCRhTXuboU1e5A+M4NvPjPHjh8xN3EfMRCMTC/uc0wvh4jmLXd35i1qhAUtlHsFLf9/uCzLzGJIy8yuSjMzYkgzM65Ky8wzNcvMgDczMzM1MzOANzMzkYjLzJGIMzPeisvM3oozMyZwy8wmcDMzc3LLzHNyMzMLPjMzvjvLzAs+y8y+OzMzgDczMzM1y8yAN8vMMzUzM0Jay8xCWjMzjlzLzI5cy8y+O8vMCz4zM747MzMLPsvMc3IzM3Nyy8wmcDMzJnDLzN6KMzPeisvMkYgzM5GI"),
|
||||||
|
"format": 34896613399,
|
||||||
|
"index_count": 18,
|
||||||
|
"index_data": PackedByteArray("VgBUAFUAVQBXAFYAVwBYAFYAWwBZAFoAWgBcAFsAXABdAFsA"),
|
||||||
|
"material": SubResource("StandardMaterial3D_8qvhc"),
|
||||||
|
"name": "darkMetal",
|
||||||
|
"primitive": 3,
|
||||||
|
"uv_scale": Vector4(5.90551, 11.4488, 0, 0),
|
||||||
|
"vertex_count": 168,
|
||||||
|
"vertex_data": PackedByteArray("AABxLszM9eAAAP8fk5714FVVcS7MzPXgVVX/H5Oe9eCpqnEuzMz14Kmq/x+TnvXg//9xLszM9eD///8fk5714AAA/x+TnlTVAAD/HzMzVNVVVf8fk55U1VVV/x8zM1TVqapU1TMzVNWpqlTVzMxU1f//VNUzM1TV//9U1czMVNX///8fMzP//6mq/x8zM/////9U1TMz//+pqlTVMzP//wAAVNUzM1TVAABU1czMVNVVVVTVMzNU1VVVVNXMzFTVVVX/HzMz//8AAP8fMzP//1VVVNUzM///AABU1TMz//8AAHEuzMz//1VVcS7MzP//AABU1czM//9VVVTVzMz//6mqcS7MzP////9xLszM//+pqlTVzMz/////VNXMzP//AACqGv//VNUAAFTVzMxU1QAAVPX//1TVAABU9QAAVNUAAFTVMzNU1QAA/x8zM1TVAABxLszMVNUAAAAAqapU1QAA/x+TnlTVAAAAAAAAVNX//1T1//9U1f//cS7MzFTV//+qGv//VNX//wAAqapU1f///x+TnlTV//8AAAAAVNX///8fMzNU1f//VNUzM1TV//9U1czMVNX//1T1AABU1f//qhr/////AACqGv///////1T1/////wAAVPX/////AAAAAAAA/////wAAAAD//wAAVPUAAP////9U9QAA//8AAFT1AABU1VVVVPXMzFTVAABU9f//VNX//1T1//9U1amqVPXMzFTVqapU9TMzVNVVVVT1MzNU1f//VPUAAFTVAAAAAKmqaMsAAKoa//9oy///AACpqmjL//+qGv//aMsAAAAAAABU1QAAAACpqlTV//8AAAAAVNX//wAAqapU1amq/x+TnlTVqar/HzMzVNX///8fk55U1f///x8zM1TVVVVU1czM/79VVXEuzMz/v1VVVNUzM/+/VVX/H5Oe/79VVf8fMzP/v6mqcS7MzP+/qapU1czM/7+pqv8fk57/v6mqVNUzM/+/qar/HzMz/79VVVT1MzP//6mqVPUzM///yVYX+DMz//81qRf4MzP//wxbqfozM///8qSp+jMz//8qnt/8MzP//9Rh3/wzM///qmqR/jMz//9UlZH+MzP///R0of8zM///Couh/zMz////f///MzP//9Rh3/zMzFTV1GHf/DMzVNWqapH+zMxU1apqkf4zM1TV8qSp+szMVNUqnt/8zMxU1fKkqfozM1TVKp7f/DMzVNWpqlT1zMz//1VVVPXMzP//NakX+MzM///JVhf4zMz///KkqfrMzP//DFup+szM//8qnt/8zMz//9Rh3/zMzP//VJWR/szM//+qapH+zMz//wqLof/MzP//9HSh/8zM////f///zMz//9Rh3/zMzFTVDFup+szMVNXUYd/8MzNU1QxbqfozM1TVyVYX+MzMVNVVVVT1zMxU1clWF/gzM1TVVVVU9TMzVNX/f///zMxU1f9///8zM1TVCouh/8zMVNUKi6H/MzNU1QqLof/MzFTVCouh/zMzVNVUlZH+zMxU1VSVkf4zM1TVNakX+MzMVNXypKn6zMxU1TWpF/gzM1TV8qSp+jMzVNWpqlT1zMxU1TWpF/jMzFTVqapU9TMzVNU1qRf4MzNU1VSVkf7MzFTVVJWR/jMzVNUqnt/8zMxU1Sqe3/wzM1TVDFup+szMVNXJVhf4zMxU1QxbqfozM1TVyVYX+DMzVNWqapH+zMxU1apqkf4zM1TV9HSh/8zMVNX0dKH/MzNU1fR0of/MzFTV9HSh/zMzVNX/f///zMxU1f9///8zM1TV////f////3////9/////f////3////9/////f////3////9/////f////3////9/AAD/fwAA/38AAP9/AAD/f/9//3//f/9//3//f/9//38AAP9/AAD/fwAA/38AAP9//3//f/9//3//f/9//3//f/9/////f////3////9/////f////3////9/////f////3////9/////f////3////9/////f////3////9/////f////3////9/AAD/fwAA/38AAP9/AAD/fwAA/38AAP9/AAD/fwAA/38AAP9/AAD/f/9//3//f/9//3//f/9//3////9/////f////3///////3////9/////f////3////9/////f////3////9/AAD/fwAA/38AAP9/AAD/fwAA/38AAP9/AAD/fwAA/3////9/////f////3////9//3////9//v//f////3/+//9/////fwAA/38AAP9/AAD/fwAA/38AAP9/////f////3////9/////f////3////9/////f////3////9/////f////3////9/////v/+//7//vyXR2a4l0dmu2a7ZLv+//z/Zrtku/7//P/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//f/9//3//v/+/2a4l0f+//7/ZriXRDJvy5OOOGvEMm/Lk444a8f///3////9/8uTyZPLk8mTy5PJk8uTyZCXRJVEl0SVRDJsMG9mu2S4Mmwwb2a7ZLuOO5A4Mmwwb447kDgybDBsl0SVRJdElUf+//z//v/8/2a4l0Qyb8uTZriXRDJvy5CXR2a4l0dmu8uQMm/LkDJvy5Ayb8uQMm////3////9/")
|
||||||
|
}, {
|
||||||
|
"aabb": AABB(-0.03, -0.12, -0.075, 0.06, 0.24, 0.15),
|
||||||
|
"attribute_data": PackedByteArray("MrMGkTKzrqsQkQaREJGuq+5uBpHubq6rzEwGkcxMrqvMTCGmzEy+bu5uIabubr5u7m6+bu5u+L3MTL5uzEz4vTKzluUQkZblMrPuTxCR7k8ys75uMrP4vRCRvm4Qkfi97m6W5cxMluXubu5PzEzuTzKzqtkQkarZMrPuTxCR7k/ubqrZzEyq2e5u7k/MTO5P///86cvM7k///4U1AACFNTMz7k8zM5bly8yq2aqq//+TnpblAAD//wAAhTUzM6rZAAD86VRV//9rYZbl/////8vMluXLzO5PMzPuT///hTUys/zpzEz86TKzhTXMTIU1MrP//8xM//8ys4U1zEyFNcxMVVTubvi9zExh2DKzYdgQkfi9EJG+bu5uvm4ys1VUzEzqscxMtIAys+qxMrO0gDKzVVQys12szExVVMxMXawQkSGmEJG+bjKzIaYys75uy8zuT8vMqtkzM+5Pk56W5TMzluUzM6rZMzPuT2thluXLzO5Py8yW5RCRhTXuboU1e5A+M4NvPjPHjh8xN3EfMe5zTC8QjEwvh4jmLXd35i1qhAUtlHsFLf9/uCzLzI5cMzOOXMvMQlozM0JaMzOuSjMzYkjLzK5Ky8xiSBCRhTXuboU1e5A+M4NvPjPHjh8xN3EfMRCMTC/uc0wvh4jmLXd35i1qhAUtlHsFLf9/uCzLzGJIy8yuSjMzYkgzM65Ky8wzNcvMgDczMzM1MzOANzMzkYjLzJGIMzPeisvM3oozMyZwy8wmcDMzc3LLzHNyMzMLPjMzvjvLzAs+y8y+OzMzgDczMzM1y8yAN8vMMzUzM0Jay8xCWjMzjlzLzI5cy8y+O8vMCz4zM747MzMLPsvMc3IzM3Nyy8wmcDMzJnDLzN6KMzPeisvMkYgzM5GI"),
|
||||||
|
"format": 34896613399,
|
||||||
|
"index_count": 138,
|
||||||
|
"index_data": PackedByteArray("YABeAF8AXwBhAGAAYQBiAGAAYQBjAGIAYwBkAGIAZABlAGIAZABmAGUAZABnAGYAZwBoAGYAZwBpAGgAaQBqAGgAbQBrAGwAbABuAG0AcQBvAHAAcAByAHEAdQBzAHQAdAB2AHUAdgB3AHUAdgB4AHcAeAB5AHcAeAB6AHkAegB7AHkAegB8AHsAfAB9AHsAfAB+AH0AfgB/AH0AggCAAIEAgQCDAIIAhgCEAIUAhQCHAIYAigCIAIkAiQCLAIoAjgCMAI0AjQCPAI4AkgCQAJEAkQCTAJIAlgCUAJUAlQCXAJYAmgCYAJkAmQCbAJoAngCcAJ0AnQCfAJ4AogCgAKEAoQCjAKIApgCkAKUApQCnAKYA"),
|
||||||
|
"material": SubResource("StandardMaterial3D_mihsn"),
|
||||||
|
"name": "yellow",
|
||||||
|
"primitive": 3,
|
||||||
|
"uv_scale": Vector4(5.90551, 11.4488, 0, 0),
|
||||||
|
"vertex_count": 168,
|
||||||
|
"vertex_data": PackedByteArray("AABxLszM9eAAAP8fk5714FVVcS7MzPXgVVX/H5Oe9eCpqnEuzMz14Kmq/x+TnvXg//9xLszM9eD///8fk5714AAA/x+TnlTVAAD/HzMzVNVVVf8fk55U1VVV/x8zM1TVqapU1TMzVNWpqlTVzMxU1f//VNUzM1TV//9U1czMVNX///8fMzP//6mq/x8zM/////9U1TMz//+pqlTVMzP//wAAVNUzM1TVAABU1czMVNVVVVTVMzNU1VVVVNXMzFTVVVX/HzMz//8AAP8fMzP//1VVVNUzM///AABU1TMz//8AAHEuzMz//1VVcS7MzP//AABU1czM//9VVVTVzMz//6mqcS7MzP////9xLszM//+pqlTVzMz/////VNXMzP//AACqGv//VNUAAFTVzMxU1QAAVPX//1TVAABU9QAAVNUAAFTVMzNU1QAA/x8zM1TVAABxLszMVNUAAAAAqapU1QAA/x+TnlTVAAAAAAAAVNX//1T1//9U1f//cS7MzFTV//+qGv//VNX//wAAqapU1f///x+TnlTV//8AAAAAVNX///8fMzNU1f//VNUzM1TV//9U1czMVNX//1T1AABU1f//qhr/////AACqGv///////1T1/////wAAVPX/////AAAAAAAA/////wAAAAD//wAAVPUAAP////9U9QAA//8AAFT1AABU1VVVVPXMzFTVAABU9f//VNX//1T1//9U1amqVPXMzFTVqapU9TMzVNVVVVT1MzNU1f//VPUAAFTVAAAAAKmqaMsAAKoa//9oy///AACpqmjL//+qGv//aMsAAAAAAABU1QAAAACpqlTV//8AAAAAVNX//wAAqapU1amq/x+TnlTVqar/HzMzVNX///8fk55U1f///x8zM1TVVVVU1czMVNVVVXEuzMxU1VVVVNUzM1TVVVX/H5OeVNVVVf8fMzNU1amqcS7MzFTVqapU1czMVNWpqv8fk55U1amqVNUzM1TVqar/HzMzVNVVVVT1MzP//6mqVPUzM///yVYX+DMz//81qRf4MzP//wxbqfozM///8qSp+jMz//8qnt/8MzP//9Rh3/wzM///qmqR/jMz//9UlZH+MzP///R0of8zM///Couh/zMz////f///MzP//9Rh3/zMzPzF1GHf/DMz/MWqapH+zMxKyqpqkf4zM0rK8qSp+szMusIqnt/8zMz8xfKkqfozM7rCKp7f/DMz/MWpqlT1zMz/f1VVVPXMzP9/NakX+MzM/3/JVhf4zMz/f/KkqfrMzP9/DFup+szM/38qnt/8zMz/f9Rh3/zMzP9/VJWR/szM/3+qapH+zMz/fwqLof/MzP9/9HSh/8zM/3//f///zMz/f9Rh3/zMzPzFDFup+szMusLUYd/8MzP8xQxbqfozM7rCyVYX+MzMsMBVVVT1zMwrwMlWF/gzM7DAVVVU9TMzK8D/f///zMxU1f9///8zM1TVCouh/8zMd88Ki6H/MzN3zwqLof/MzHfPCouh/zMzd89UlZH+zMxKylSVkf4zM0rKNakX+MzMsMDypKn6zMy6wjWpF/gzM7DA8qSp+jMzusKpqlT1zMwrwDWpF/jMzLDAqapU9TMzK8A1qRf4MzOwwFSVkf7MzErKVJWR/jMzSsoqnt/8zMz8xSqe3/wzM/zFDFup+szMusLJVhf4zMywwAxbqfozM7rCyVYX+DMzsMCqapH+zMxKyqpqkf4zM0rK9HSh/8zMd8/0dKH/MzN3z/R0of/MzHfP9HSh/zMzd8//f///zMxU1f9///8zM1TV////f////3////9/////f////3////9/////f////3////9/////f////3////9/AAD/fwAA/38AAP9/AAD/f/9//3//f/9//3//f/9//38AAP9/AAD/fwAA/38AAP9//3//f/9//3//f/9//3//f/9/////f////3////9/////f////3////9/////f////3////9/////f////3////9/////f////3////9/////f////3////9/AAD/fwAA/38AAP9/AAD/fwAA/38AAP9/AAD/fwAA/38AAP9/AAD/f/9//3//f/9//3//f/9//3////9/////f////3///////3////9/////f////3////9/////f////3////9/AAD/fwAA/38AAP9/AAD/fwAA/38AAP9/AAD/fwAA/3////9/////f////3////9//3////9/////f////3////9/////fwAA/38AAP9/AAD/fwAA/38AAP9/////f////3////9/////f////3////9/////f////3////9/////f////3////9////+nADG/pwAxkuiZrtLoma7qKxUFv25/xyorFQW/bn/HP9/////f////3////9/////f////3////9/////f////3////9/////f////3////9////+nADGVJZV0/6cAMZUllXTVo1R5WqHKfFWjVHlaocp8VTVqipU1aoqf82/Jn/NvyZ/zb8mf82/JpfETCKXxEwirZpWDaisVBatmlYNqKxUFtWOagetmlYN1Y5qB62aVg2XxEwil8RMIv25/xz9uf8cVJZV01aNUeVUllXTVo1R5UuiZrtLoma7v6Z/sr+mf7K/pn+yv6Z/sqqqqqqqqqqq")
|
||||||
|
}]
|
||||||
|
blend_shape_mode = 0
|
||||||
|
shadow_mesh = SubResource("ArrayMesh_68l5q")
|
||||||
|
|
||||||
|
[sub_resource type="BoxShape3D" id="BoxShape3D_g84k4"]
|
||||||
|
size = Vector3(0.166504, 0.159378, 0.162319)
|
||||||
|
|
||||||
|
[node name="blasterM_clip" type="RigidBody3D"]
|
||||||
|
collision_layer = 8
|
||||||
|
collision_mask = 5
|
||||||
|
script = ExtResource("1_qqhy0")
|
||||||
|
weapon = SubResource("Resource_jnsso")
|
||||||
|
TYPE = "Ammo"
|
||||||
|
|
||||||
|
[node name="clipA2" type="MeshInstance3D" parent="."]
|
||||||
|
transform = Transform3D(2.76, 0, 0, 0, -0.695, 9.66022e-08, 0, -6.07588e-08, -1.105, 0, 0, 0)
|
||||||
|
mesh = SubResource("ArrayMesh_5ckjg")
|
||||||
|
skeleton = NodePath("")
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 5.53727e-05, 0.00519562, 0.00165367)
|
||||||
|
shape = SubResource("BoxShape3D_g84k4")
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
[gd_scene load_steps=11 format=4 uid="uid://cjxvrad2c6vh8"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://deaf6cmuofa0" path="res://client/template/scripts/Weapon_State_Machine/PickUp Weapons/Weapon_Pick_Up.gd" id="1_d1wy0"]
|
||||||
|
[ext_resource type="Script" uid="uid://bw4j1fbww4k8s" path="res://client/template/scripts/Weapon_State_Machine/WeaponSlot.gd" id="2_tnv4c"]
|
||||||
|
[ext_resource type="Resource" uid="uid://c1jg0ifn7yvve" path="res://client/template/scripts/Weapon_State_Machine/Weapon_Resources/blasterN.tres" id="3_x72lj"]
|
||||||
|
|
||||||
|
[sub_resource type="Resource" id="Resource_8ete7"]
|
||||||
|
resource_local_to_scene = true
|
||||||
|
script = ExtResource("2_tnv4c")
|
||||||
|
weapon = ExtResource("3_x72lj")
|
||||||
|
current_ammo = 5
|
||||||
|
reserve_ammo = 0
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_n3ik4"]
|
||||||
|
resource_name = "metal"
|
||||||
|
vertex_color_use_as_albedo = true
|
||||||
|
albedo_color = Color(0.904365, 0.914141, 0.944534, 1)
|
||||||
|
metallic = 1.0
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_fil5e"]
|
||||||
|
resource_name = "darkMetal"
|
||||||
|
vertex_color_use_as_albedo = true
|
||||||
|
albedo_color = Color(0.793075, 0.81829, 0.89044, 1)
|
||||||
|
metallic = 1.0
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_bfdxb"]
|
||||||
|
resource_name = "yellow"
|
||||||
|
vertex_color_use_as_albedo = true
|
||||||
|
albedo_color = Color(0.998274, 0.894448, 0.505969, 1)
|
||||||
|
metallic = 1.0
|
||||||
|
|
||||||
|
[sub_resource type="ArrayMesh" id="ArrayMesh_j3k8o"]
|
||||||
|
_surfaces = [{
|
||||||
|
"aabb": AABB(-0.03, -0.12, -0.075, 0.06, 0.24, 0.15),
|
||||||
|
"format": 34359742465,
|
||||||
|
"index_count": 168,
|
||||||
|
"index_data": PackedByteArray("AgAAAAEAAQADAAIABgAEAAUABQAHAAYAAwABAAgACAAJAAMADAAKAAsACwANAAwADAAOAA8ADwAKAAwAEgAQABEAEQATABIAEgAJAAgACAAQABIAEQAAAAIAAgATABEACwAEAAYABgANAAsAFQAUABEAEQAWABUAEQAQABYAEAAIABYAAAARABQAFAAXAAAAFwABAAAAFwAYAAEAGAAIAAEAGAAWAAgAGgAZAAYABgAbABoABgAHABsABwAcABsABwAOABwADgAMABwADQAGABkAGQAdAA0AHQAMAA0AHQAcAAwAGQAaABQAFAAVABkAFgAYABwAHAAdABYAFQAWAB4AHgAZABUAHgAfABkAHwAgABkAIQAeABYAFgAdACEAHQAgACEAHQAZACAAGwAXABQAFAAaABsAHAAYABcAFwAbABwABwAFAA8ADwAOAAcA"),
|
||||||
|
"name": "metal",
|
||||||
|
"primitive": 3,
|
||||||
|
"uv_scale": Vector4(0, 0, 0, 0),
|
||||||
|
"vertex_count": 56,
|
||||||
|
"vertex_data": PackedByteArray("kML1vIaWnL3rUTg9kML1vOtRuL2wyJI8CtcjvIaWnL3rUTg9CtcjvOtRuL2wyJI8CtcjPIaWnL3rUTg9CtcjPOtRuL2wyJI8kML1PIaWnL3rUTg9kML1POtRuL2wyJI8kML1vOtRuL3rUTi9CtcjvOtRuL3rUTi9CtcjPArXoz3rUTi9CtcjPArXoz3rUTg9kML1PArXoz3rUTi9kML1PArXoz3rUTg9kML1POtRuL3rUTi9CtcjPOtRuL3rUTi9kML1vArXoz3rUTi9kML1vArXoz3rUTg9CtcjvArXoz3rUTi9CtcjvArXoz3rUTg9kML1vFyPwr2amZk9kML1vK1H4T2amZk9kML1vK1H4T2amZm9kML1vJDC9b3NzMw8kML1vJDC9b2amZm9kML1PK1H4T2amZk9kML1PFyPwr2amZk9kML1PJDC9b3NzMw8kML1PJDC9b2amZm9kML1PK1H4T2amZm9CtcjvK1H4T3rUTg9CtcjPK1H4T3rUTg9CtcjPK1H4T3rUTi9CtcjvK1H4T3rUTi93kEevKKU5j3rUTi93kEePKKU5j3rUTi9vOMNvB+F6z3rUTi9vOMNPB+F6z3rUTi9a7TnO/TC7z3rUTi9a7Tnu/TC7z3rUTi9CtejuyYE8z3rUTi9CtejOyYE8z3rUTi9oZ4pu+kP9T3rUTi9oZ4pO+kP9T3rUTi9AAAAAJDC9T3rUTi9a7Tnu/TC7z3rUTg9CtejuyYE8z3rUTg9vOMNPB+F6z3rUTg9a7TnO/TC7z3rUTg93kEePKKU5j3rUTg93kEevKKU5j3rUTg9vOMNvB+F6z3rUTg9CtejOyYE8z3rUTg9oZ4pO+kP9T3rUTg9oZ4pu+kP9T3rUTg9AAAAAJDC9T3rUTg9")
|
||||||
|
}, {
|
||||||
|
"aabb": AABB(-0.03, -0.12, -0.075, 0.06, 0.24, 0.15),
|
||||||
|
"format": 34359742465,
|
||||||
|
"index_count": 18,
|
||||||
|
"index_data": PackedByteArray("EgATAAIAAgADABIAAwAJABIABQAEAAsACwAKAAUACgAPAAUA"),
|
||||||
|
"name": "darkMetal",
|
||||||
|
"primitive": 3,
|
||||||
|
"uv_scale": Vector4(0, 0, 0, 0),
|
||||||
|
"vertex_count": 56,
|
||||||
|
"vertex_data": PackedByteArray("kML1vIaWnL3rUTg9kML1vOtRuL2wyJI8CtcjvIaWnL3rUTg9CtcjvOtRuL2wyJI8CtcjPIaWnL3rUTg9CtcjPOtRuL2wyJI8kML1PIaWnL3rUTg9kML1POtRuL2wyJI8kML1vOtRuL3rUTi9CtcjvOtRuL3rUTi9CtcjPArXoz3rUTi9CtcjPArXoz3rUTg9kML1PArXoz3rUTi9kML1PArXoz3rUTg9kML1POtRuL3rUTi9CtcjPOtRuL3rUTi9kML1vArXoz3rUTi9kML1vArXoz3rUTg9CtcjvArXoz3rUTi9CtcjvArXoz3rUTg9kML1vFyPwr2amZk9kML1vK1H4T2amZk9kML1vK1H4T2amZm9kML1vJDC9b3NzMw8kML1vJDC9b2amZm9kML1PK1H4T2amZk9kML1PFyPwr2amZk9kML1PJDC9b3NzMw8kML1PJDC9b2amZm9kML1PK1H4T2amZm9CtcjvK1H4T3rUTg9CtcjPK1H4T3rUTg9CtcjPK1H4T3rUTi9CtcjvK1H4T3rUTi93kEevKKU5j3rUTi93kEePKKU5j3rUTi9vOMNvB+F6z3rUTi9vOMNPB+F6z3rUTi9a7TnO/TC7z3rUTi9a7Tnu/TC7z3rUTi9CtejuyYE8z3rUTi9CtejOyYE8z3rUTi9oZ4pu+kP9T3rUTi9oZ4pO+kP9T3rUTi9AAAAAJDC9T3rUTi9a7Tnu/TC7z3rUTg9CtejuyYE8z3rUTg9vOMNPB+F6z3rUTg9a7TnO/TC7z3rUTg93kEePKKU5j3rUTg93kEevKKU5j3rUTg9vOMNvB+F6z3rUTg9CtejOyYE8z3rUTg9oZ4pO+kP9T3rUTg9oZ4pu+kP9T3rUTg9AAAAAJDC9T3rUTg9")
|
||||||
|
}, {
|
||||||
|
"aabb": AABB(-0.03, -0.12, -0.075, 0.06, 0.24, 0.15),
|
||||||
|
"format": 34359742465,
|
||||||
|
"index_count": 138,
|
||||||
|
"index_data": PackedByteArray("IgAhACAAIAAjACIAIwAkACIAIwAlACQAJQAmACQAJgAnACQAJgAoACcAJgApACgAKQAqACgAKQArACoAKwAsACoALgAtACcAJwAoAC4AJQAvADAAMAAmACUAMQAfAB4AHgAyADEAMgAvADEAMgAzAC8AMwAwAC8AMwAtADAALQA0ADAALQAuADQALgA1ADQALgA2ADUANgA3ADUAJwAtADMAMwAkACcAIgAyAB4AHgAhACIANQA3ACwALAArADUANAA1ACsAKwApADQAIwAxAC8ALwAlACMAIAAfADEAMQAjACAAMAA0ACkAKQAmADAAJAAzADIAMgAiACQANgAuACgAKAAqADYANwA2ACoAKgAsADcA"),
|
||||||
|
"name": "yellow",
|
||||||
|
"primitive": 3,
|
||||||
|
"uv_scale": Vector4(0, 0, 0, 0),
|
||||||
|
"vertex_count": 56,
|
||||||
|
"vertex_data": PackedByteArray("kML1vIaWnL3rUTg9kML1vOtRuL2wyJI8CtcjvIaWnL3rUTg9CtcjvOtRuL2wyJI8CtcjPIaWnL3rUTg9CtcjPOtRuL2wyJI8kML1PIaWnL3rUTg9kML1POtRuL2wyJI8kML1vOtRuL3rUTi9CtcjvOtRuL3rUTi9CtcjPArXoz3rUTi9CtcjPArXoz3rUTg9kML1PArXoz3rUTi9kML1PArXoz3rUTg9kML1POtRuL3rUTi9CtcjPOtRuL3rUTi9kML1vArXoz3rUTi9kML1vArXoz3rUTg9CtcjvArXoz3rUTi9CtcjvArXoz3rUTg9kML1vFyPwr2amZk9kML1vK1H4T2amZk9kML1vK1H4T2amZm9kML1vJDC9b3NzMw8kML1vJDC9b2amZm9kML1PK1H4T2amZk9kML1PFyPwr2amZk9kML1PJDC9b3NzMw8kML1PJDC9b2amZm9kML1PK1H4T2amZm9CtcjvK1H4T3rUTg9CtcjPK1H4T3rUTg9CtcjPK1H4T3rUTi9CtcjvK1H4T3rUTi93kEevKKU5j3rUTi93kEePKKU5j3rUTi9vOMNvB+F6z3rUTi9vOMNPB+F6z3rUTi9a7TnO/TC7z3rUTi9a7Tnu/TC7z3rUTi9CtejuyYE8z3rUTi9CtejOyYE8z3rUTi9oZ4pu+kP9T3rUTi9oZ4pO+kP9T3rUTi9AAAAAJDC9T3rUTi9a7Tnu/TC7z3rUTg9CtejuyYE8z3rUTg9vOMNPB+F6z3rUTg9a7TnO/TC7z3rUTg93kEePKKU5j3rUTg93kEevKKU5j3rUTg9vOMNvB+F6z3rUTg9CtejOyYE8z3rUTg9oZ4pO+kP9T3rUTg9oZ4pu+kP9T3rUTg9AAAAAJDC9T3rUTg9")
|
||||||
|
}]
|
||||||
|
blend_shape_mode = 0
|
||||||
|
|
||||||
|
[sub_resource type="ArrayMesh" id="ArrayMesh_py3xv"]
|
||||||
|
resource_name = "clipA_Mesh clipA"
|
||||||
|
_surfaces = [{
|
||||||
|
"aabb": AABB(-0.03, -0.12, -0.075, 0.06, 0.24, 0.15),
|
||||||
|
"attribute_data": PackedByteArray("XS6XP0T3Qj9dLpc/dxH6PyaTyT5E90I/JpPJPncR+j8mk8m+RPdCPyaTyb53Efo/XS6Xv0T3Qj9dLpe/dxH6P10ul7+US9o/XS6XvxaLRb8mk8m+lEvaPyaTyb4Wi0W/JpPJvhaLRb8mk8m+xmIxQF0ul78Wi0W/XS6Xv8ZiMUBdLpc/xmKRQCaTyT7GYpFAXS6XPyaTCcAmk8k+JpMJwF0ulz8Wi0W/XS6XP8ZiMUAmk8k+FotFvyaTyT7GYjFAJpPJvsZikUBdLpe/xmKRQCaTyb4mkwnAXS6XvyaTCcBdLpc/hlOAQCaTyT6GU4BAXS6XPyaTCcAmk8k+JpMJwCaTyb6GU4BAXS6Xv4ZTgEAmk8m+JpMJwF0ul78mkwnA9Pk8QF6vl0CLxeI/JpMJwPT5PEBUKlXA9Pk8wFQqVcCLxeK/JpMJwIvF4r/GYpFAi8XiP4ZTgEDw93s/XS63QCmXND/GYpFA9Pk8wF0ut0D0+TzAVCpVwIvF4r+GU4BA9Pk8wF6vl0Dw93u/XS63QCmXNL/GYpFA9Pk8QF0ut0CLxeI/xmKRQIvF4j8mkwnAi8XivyaTCcD0+TxAVCpVwF0ulz9er5dAXS6Xv16vl0BdLpc/VCpVwF0ul79UKlXAXS6XP10ut0BdLpe/XS63QF0ulz9UKlXAXS6Xv1QqVcBdLpe/6PP5vyaTyb7GYjFAXS6Xv/T5fEBdLpc/9Pl8QCaTyT7GYjFAJpPJPhaLRb8mk8m+FotFv10ulz/o8/m/XS6Xv+3gDkBdLpe/QIgBPV0ulz/t4A5AXS6XP0CIAT1dLpc/6PP5v10ulz/4+/0/XS6Xv+jz+b9dLpe/+Pv9PyaTyT6US9o/JpPJPhaLRb9dLpc/lEvaP10ulz8Wi0W/i8XiPyaTCcCLxeI/hlOAQIvF4r8mkwnAKZc0P8ZikUCLxeK/xmKRQIvF4r+GU4BAi8XivyaTCcAplzS/xmKRQIvF4j8mkwnAi8XiP8ZikUAmk8k+VCpVwCaTyb5UKlXA0bTCPtCvW8DRtMK+0K9bwKORrj6Iw2HAo5GuvojDYcDwiI6+cvtmwPCIjj5y+2bAJpNJPor8asAmk0m+ivxqwIOv0D3ugG3Ag6/Qve6AbcDxsKoOulxuwIvF4j+g4Mq/i8Xiv6Dgyr+LxeI/agjYv4vF4r9qCNi/i8Xiv+mZGMCLxeK/zS0fwIvF4j/pmRjAi8XiP80tH8Amk8k+VCpVwCaTyb5UKlXA0bTCPtCvW8DRtMK+0K9bwKORrj6Iw2HAo5GuvojDYcDwiI4+cvtmwPCIjr5y+2bAJpNJPor8asAmk0m+ivxqwIOv0D3ugG3Ag6/Qve6AbcAJafYNulxuwIvF4j/NLR/Ai8XiP+mZGMCLxeK/zS0fwIvF4r/pmRjAi8XiP0AVVsCLxeI/XIFPwIvF4r9AFVbAi8Xiv1yBT8CLxeK/QEXEPovF4j9ARcQ+i8Xiv2Dk+D6LxeI/YOT4PovF4r/4azW/i8XiP/hrNb+LxeK/aBwbv4vF4j9oHBu/i8Xiv0/HPMCLxeK/MltDwIvF4j9PxzzAi8XiPzJbQ8CLxeK/XIFPwIvF4r9AFVbAi8XiP1yBT8CLxeI/QBVWwIvF4r9qCNi/i8XiP2oI2L+LxeK/oODKv4vF4j+g4Mq/i8XiPzJbQ8CLxeI/T8c8wIvF4r8yW0PAi8Xiv0/HPMCLxeI/aBwbv4vF4r9oHBu/i8XiP/hrNb+LxeK/+Gs1v4vF4j9g5Pg+i8Xiv2Dk+D6LxeI/QEXEPovF4r9ARcQ+"),
|
||||||
|
"format": 34359742487,
|
||||||
|
"index_count": 168,
|
||||||
|
"index_data": PackedByteArray("AgAAAAEAAQADAAIABgAEAAUABQAHAAYACgAIAAkACQALAAoADgAMAA0ADQAPAA4AEgAQABEAEQATABIAFgAUABUAFQAXABYAGgAYABkAGQAbABoAHgAcAB0AHQAfAB4AIgAgACEAIQAjACIAJgAkACUAJQAnACYAJQAoACcAKAApACcAKgAlACQAJAArACoAKwAsACoAKwAtACwALQApACwALQAnACkAMAAuAC8ALwAxADAALwAyADEAMgAzADEAMgA0ADMANAA1ADMANgAvAC4ALgA3ADYANwA1ADYANwAzADUAOgA4ADkAOQA7ADoAPgA8AD0APQA/AD4AQgBAAEEAQQBDAEIAQQBEAEMARABFAEMARgBBAEAAQABHAEYARwBFAEYARwBDAEUASgBIAEkASQBLAEoATgBMAE0ATQBPAE4AUgBQAFEAUQBTAFIA"),
|
||||||
|
"material": SubResource("StandardMaterial3D_n3ik4"),
|
||||||
|
"name": "metal",
|
||||||
|
"primitive": 3,
|
||||||
|
"uv_scale": Vector4(0, 0, 0, 0),
|
||||||
|
"vertex_count": 168,
|
||||||
|
"vertex_data": PackedByteArray("kML1vIaWnL3rUTg9kML1vOtRuL2wyJI8CtcjvIaWnL3rUTg9CtcjvOtRuL2wyJI8CtcjPIaWnL3rUTg9CtcjPOtRuL2wyJI8kML1PIaWnL3rUTg9kML1POtRuL2wyJI8kML1vOtRuL2wyJI8kML1vOtRuL3rUTi9CtcjvOtRuL2wyJI8CtcjvOtRuL3rUTi9CtcjPArXoz3rUTi9CtcjPArXoz3rUTg9kML1PArXoz3rUTi9kML1PArXoz3rUTg9kML1POtRuL3rUTi9CtcjPOtRuL3rUTi9kML1PArXoz3rUTi9CtcjPArXoz3rUTi9kML1vArXoz3rUTi9kML1vArXoz3rUTg9CtcjvArXoz3rUTi9CtcjvArXoz3rUTg9CtcjvOtRuL3rUTi9kML1vOtRuL3rUTi9CtcjvArXoz3rUTi9kML1vArXoz3rUTi9kML1vIaWnL3rUTg9CtcjvIaWnL3rUTg9kML1vArXoz3rUTg9CtcjvArXoz3rUTg9CtcjPIaWnL3rUTg9kML1PIaWnL3rUTg9CtcjPArXoz3rUTg9kML1PArXoz3rUTg9kML1vFyPwr2amZk9kML1vArXoz3rUTg9kML1vK1H4T2amZk9kML1vK1H4T2amZm9kML1vArXoz3rUTi9kML1vOtRuL3rUTi9kML1vIaWnL3rUTg9kML1vJDC9b3NzMw8kML1vOtRuL2wyJI8kML1vJDC9b2amZm9kML1PK1H4T2amZk9kML1PIaWnL3rUTg9kML1PFyPwr2amZk9kML1PJDC9b3NzMw8kML1POtRuL2wyJI8kML1PJDC9b2amZm9kML1POtRuL3rUTi9kML1PArXoz3rUTi9kML1PArXoz3rUTg9kML1PK1H4T2amZm9kML1PFyPwr2amZk9kML1vFyPwr2amZk9kML1PK1H4T2amZk9kML1vK1H4T2amZk9kML1vJDC9b2amZm9kML1PJDC9b2amZm9kML1vK1H4T2amZm9kML1PK1H4T2amZm9kML1vK1H4T2amZm9CtcjvK1H4T3rUTg9kML1vK1H4T2amZk9kML1PK1H4T2amZk9CtcjPK1H4T3rUTg9CtcjPK1H4T3rUTi9CtcjvK1H4T3rUTi9kML1PK1H4T2amZm9kML1vJDC9b3NzMw8kML1vFyPwr2amZk9kML1PJDC9b3NzMw8kML1PFyPwr2amZk9kML1vJDC9b2amZm9kML1vJDC9b3NzMw8kML1PJDC9b2amZm9kML1PJDC9b3NzMw8CtcjPOtRuL2wyJI8CtcjPOtRuL3rUTi9kML1POtRuL2wyJI8kML1POtRuL3rUTi9CtcjvArXoz3rUTg9CtcjvIaWnL3rUTg9CtcjvArXoz3rUTi9CtcjvOtRuL2wyJI8CtcjvOtRuL3rUTi9CtcjPIaWnL3rUTg9CtcjPArXoz3rUTg9CtcjPOtRuL2wyJI8CtcjPArXoz3rUTi9CtcjPOtRuL3rUTi9CtcjvK1H4T3rUTi9CtcjPK1H4T3rUTi93kEevKKU5j3rUTi93kEePKKU5j3rUTi9vOMNvB+F6z3rUTi9vOMNPB+F6z3rUTi9a7TnO/TC7z3rUTi9a7Tnu/TC7z3rUTi9CtejuyYE8z3rUTi9CtejOyYE8z3rUTi9oZ4pu+kP9T3rUTi9oZ4pO+kP9T3rUTi9AAAAAJDC9T3rUTi9a7Tnu/TC7z3rUTg9a7Tnu/TC7z3rUTi9CtejuyYE8z3rUTg9CtejuyYE8z3rUTi9vOMNPB+F6z3rUTg9a7TnO/TC7z3rUTg9vOMNPB+F6z3rUTi9a7TnO/TC7z3rUTi9CtcjPK1H4T3rUTg9CtcjvK1H4T3rUTg93kEePKKU5j3rUTg93kEevKKU5j3rUTg9vOMNPB+F6z3rUTg9vOMNvB+F6z3rUTg9a7TnO/TC7z3rUTg9a7Tnu/TC7z3rUTg9CtejOyYE8z3rUTg9CtejuyYE8z3rUTg9oZ4pO+kP9T3rUTg9oZ4pu+kP9T3rUTg9AAAAAJDC9T3rUTg9a7Tnu/TC7z3rUTg9vOMNvB+F6z3rUTg9a7Tnu/TC7z3rUTi9vOMNvB+F6z3rUTi93kEevKKU5j3rUTg9CtcjvK1H4T3rUTg93kEevKKU5j3rUTi9CtcjvK1H4T3rUTi9AAAAAJDC9T3rUTg9AAAAAJDC9T3rUTi9oZ4pO+kP9T3rUTg9oZ4pO+kP9T3rUTi9oZ4pO+kP9T3rUTg9oZ4pO+kP9T3rUTi9CtejOyYE8z3rUTg9CtejOyYE8z3rUTi93kEePKKU5j3rUTg9vOMNPB+F6z3rUTg93kEePKKU5j3rUTi9vOMNPB+F6z3rUTi9CtcjPK1H4T3rUTg93kEePKKU5j3rUTg9CtcjPK1H4T3rUTi93kEePKKU5j3rUTi9CtejOyYE8z3rUTg9CtejOyYE8z3rUTi9a7TnO/TC7z3rUTg9a7TnO/TC7z3rUTi9vOMNvB+F6z3rUTg93kEevKKU5j3rUTg9vOMNvB+F6z3rUTi93kEevKKU5j3rUTi9CtejuyYE8z3rUTg9CtejuyYE8z3rUTi9oZ4pu+kP9T3rUTg9oZ4pu+kP9T3rUTi9oZ4pu+kP9T3rUTg9oZ4pu+kP9T3rUTi9AAAAAJDC9T3rUTg9AAAAAJDC9T3rUTi9qar//wAA/7+pqv//AAD/v6mq//8AAP+/qar//wAA/7+pqv//AAD/v6mq//8AAP+/qar//wAA/7+pqv//AAD/v/9///////+//3///////7//f///////v/9///////+//38AAAAA/7//fwAAAAD/v/9/AAAAAP+//38AAAAA/7//f/9/////v/9//3////+//3//f////7//f/9/////v/9/AAAAAP+//38AAAAA/7//fwAAAAD/v/9/AAAAAP+//3//f////7//f/9/////v/9//3////+//3//f////7//////AAD/v/////8AAP+//////wAA/7//////AAD/v/////8AAP+//////wAA/7//////AAD/v/////8AAP+/AAD/f/9//78AAP9//3//vwAA/3//f/+/AAD/f/9//78AAP9//3//vwAA/3//f/+/AAD/f/9//78AAP9//3//vwAA/3//f/+/AAD/f/9//7////9//////////3/+////////f/7///////9//v///////3/+////////f/7/AID///9//v8AgP///3///wCA////f/////////9///////9//3////+//3//f////7//f/9/////v/9//3////+//////wAA/7//////AAD/v/////8AAP+//////wAA/7//f///////v/9///////+//3///////7//f////v//v/9////+//+//3///////7//f////v//v/9///////+//3+qKv///7//f6oq////v/9/qir///+//3+qKv///7//fwAAAAD/v/9/AAAAAP+//38AAAAA/7//fwAAAAD/v/9///////+//3///////7//f///////v/9///////+/AAD/fwAAAIAAAP9/AAAAgAAA/38AAACAAAD/fwAAAIAAAP9/AAAAgP///38AAACA////fwAAAID///9/AAAAgP///38AAACA////fwAAAID/////AAAAgP////8AAACA/////wAAAID/////AAAAgP////8AAACA/////wAAAID/////AAAAgP////8AAACA/////wAAAID/////AAAAgP////8AAACA/////wAAAID/////AAAAgP8//78AAACA/z//vwAAAIAlUSXRAAAAgCVRJdEAAACAJdHZrgAAAID/v/+/AAAAgCXR2a4AAACA/7//vwAAAID/f/9/AAAAgP9//38AAACA/3//fwAAAID/f/9/AAAAgP9//38AAACA/3//fwAAAID/f/9/AAAAgP9//38AAACA/3//fwAAAID/f/9/AAAAgP9//38AAACA/3//fwAAAID/f/9/AAAAgP8//78AAACA2S7ZrgAAAID/P/+/AAAAgNku2a4AAACADBsMmwAAAIDkDuOOAAAAgAwbDJsAAACA5A7jjgAAAID/f///AAAAgP9///8AAACADJvy5AAAAIAMm/LkAAAAgAyb8uQAAACADJvy5AAAAIDZriXRAAAAgNmuJdEAAACA8uQMmwAAAIAl0dmuAAAAgPLkDJsAAACAJdHZrgAAAIAa8eOOAAAAgPLkDJsAAACAGvHjjgAAAIDy5AybAAAAgNmuJdEAAACA2a4l0QAAAID/v/+/AAAAgP+//78AAACA2S7ZrgAAAIAMGwybAAAAgNku2a4AAACADBsMmwAAAIAlUSXRAAAAgCVRJdEAAACA8mTy5AAAAIDyZPLkAAAAgPJk8uQAAACA8mTy5AAAAID/f///AAAAgP9///8AAACA")
|
||||||
|
}, {
|
||||||
|
"aabb": AABB(-0.03, -0.12, -0.075, 0.06, 0.24, 0.15),
|
||||||
|
"attribute_data": PackedByteArray("XS6XP0T3Qj9dLpc/dxH6PyaTyT5E90I/JpPJPncR+j8mk8m+RPdCPyaTyb53Efo/XS6Xv0T3Qj9dLpe/dxH6P10ul7+US9o/XS6XvxaLRb8mk8m+lEvaPyaTyb4Wi0W/JpPJvhaLRb8mk8m+xmIxQF0ul78Wi0W/XS6Xv8ZiMUBdLpc/xmKRQCaTyT7GYpFAXS6XPyaTCcAmk8k+JpMJwF0ulz8Wi0W/XS6XP8ZiMUAmk8k+FotFvyaTyT7GYjFAJpPJvsZikUBdLpe/xmKRQCaTyb4mkwnAXS6XvyaTCcBdLpc/hlOAQCaTyT6GU4BAXS6XPyaTCcAmk8k+JpMJwCaTyb6GU4BAXS6Xv4ZTgEAmk8m+JpMJwF0ul78mkwnA9Pk8QF6vl0CLxeI/JpMJwPT5PEBUKlXA9Pk8wFQqVcCLxeK/JpMJwIvF4r/GYpFAi8XiP4ZTgEDw93s/XS63QCmXND/GYpFA9Pk8wF0ut0D0+TzAVCpVwIvF4r+GU4BA9Pk8wF6vl0Dw93u/XS63QCmXNL/GYpFA9Pk8QF0ut0CLxeI/xmKRQIvF4j8mkwnAi8XivyaTCcD0+TxAVCpVwF0ulz9er5dAXS6Xv16vl0BdLpc/VCpVwF0ul79UKlXAXS6XP10ut0BdLpe/XS63QF0ulz9UKlXAXS6Xv1QqVcBdLpe/6PP5vyaTyb7GYjFAXS6Xv/T5fEBdLpc/9Pl8QCaTyT7GYjFAJpPJPhaLRb8mk8m+FotFv10ulz/o8/m/XS6Xv+3gDkBdLpe/QIgBPV0ulz/t4A5AXS6XP0CIAT1dLpc/6PP5v10ulz/4+/0/XS6Xv+jz+b9dLpe/+Pv9PyaTyT6US9o/JpPJPhaLRb9dLpc/lEvaP10ulz8Wi0W/i8XiPyaTCcCLxeI/hlOAQIvF4r8mkwnAKZc0P8ZikUCLxeK/xmKRQIvF4r+GU4BAi8XivyaTCcAplzS/xmKRQIvF4j8mkwnAi8XiP8ZikUAmk8k+VCpVwCaTyb5UKlXA0bTCPtCvW8DRtMK+0K9bwKORrj6Iw2HAo5GuvojDYcDwiI6+cvtmwPCIjj5y+2bAJpNJPor8asAmk0m+ivxqwIOv0D3ugG3Ag6/Qve6AbcDxsKoOulxuwIvF4j+g4Mq/i8Xiv6Dgyr+LxeI/agjYv4vF4r9qCNi/i8Xiv+mZGMCLxeK/zS0fwIvF4j/pmRjAi8XiP80tH8Amk8k+VCpVwCaTyb5UKlXA0bTCPtCvW8DRtMK+0K9bwKORrj6Iw2HAo5GuvojDYcDwiI4+cvtmwPCIjr5y+2bAJpNJPor8asAmk0m+ivxqwIOv0D3ugG3Ag6/Qve6AbcAJafYNulxuwIvF4j/NLR/Ai8XiP+mZGMCLxeK/zS0fwIvF4r/pmRjAi8XiP0AVVsCLxeI/XIFPwIvF4r9AFVbAi8Xiv1yBT8CLxeK/QEXEPovF4j9ARcQ+i8Xiv2Dk+D6LxeI/YOT4PovF4r/4azW/i8XiP/hrNb+LxeK/aBwbv4vF4j9oHBu/i8Xiv0/HPMCLxeK/MltDwIvF4j9PxzzAi8XiPzJbQ8CLxeK/XIFPwIvF4r9AFVbAi8XiP1yBT8CLxeI/QBVWwIvF4r9qCNi/i8XiP2oI2L+LxeK/oODKv4vF4j+g4Mq/i8XiPzJbQ8CLxeI/T8c8wIvF4r8yW0PAi8Xiv0/HPMCLxeI/aBwbv4vF4r9oHBu/i8XiP/hrNb+LxeK/+Gs1v4vF4j9g5Pg+i8Xiv2Dk+D6LxeI/QEXEPovF4r9ARcQ+"),
|
||||||
|
"format": 34359742487,
|
||||||
|
"index_count": 18,
|
||||||
|
"index_data": PackedByteArray("VgBUAFUAVQBXAFYAVwBYAFYAWwBZAFoAWgBcAFsAXABdAFsA"),
|
||||||
|
"material": SubResource("StandardMaterial3D_fil5e"),
|
||||||
|
"name": "darkMetal",
|
||||||
|
"primitive": 3,
|
||||||
|
"uv_scale": Vector4(0, 0, 0, 0),
|
||||||
|
"vertex_count": 168,
|
||||||
|
"vertex_data": PackedByteArray("kML1vIaWnL3rUTg9kML1vOtRuL2wyJI8CtcjvIaWnL3rUTg9CtcjvOtRuL2wyJI8CtcjPIaWnL3rUTg9CtcjPOtRuL2wyJI8kML1PIaWnL3rUTg9kML1POtRuL2wyJI8kML1vOtRuL2wyJI8kML1vOtRuL3rUTi9CtcjvOtRuL2wyJI8CtcjvOtRuL3rUTi9CtcjPArXoz3rUTi9CtcjPArXoz3rUTg9kML1PArXoz3rUTi9kML1PArXoz3rUTg9kML1POtRuL3rUTi9CtcjPOtRuL3rUTi9kML1PArXoz3rUTi9CtcjPArXoz3rUTi9kML1vArXoz3rUTi9kML1vArXoz3rUTg9CtcjvArXoz3rUTi9CtcjvArXoz3rUTg9CtcjvOtRuL3rUTi9kML1vOtRuL3rUTi9CtcjvArXoz3rUTi9kML1vArXoz3rUTi9kML1vIaWnL3rUTg9CtcjvIaWnL3rUTg9kML1vArXoz3rUTg9CtcjvArXoz3rUTg9CtcjPIaWnL3rUTg9kML1PIaWnL3rUTg9CtcjPArXoz3rUTg9kML1PArXoz3rUTg9kML1vFyPwr2amZk9kML1vArXoz3rUTg9kML1vK1H4T2amZk9kML1vK1H4T2amZm9kML1vArXoz3rUTi9kML1vOtRuL3rUTi9kML1vIaWnL3rUTg9kML1vJDC9b3NzMw8kML1vOtRuL2wyJI8kML1vJDC9b2amZm9kML1PK1H4T2amZk9kML1PIaWnL3rUTg9kML1PFyPwr2amZk9kML1PJDC9b3NzMw8kML1POtRuL2wyJI8kML1PJDC9b2amZm9kML1POtRuL3rUTi9kML1PArXoz3rUTi9kML1PArXoz3rUTg9kML1PK1H4T2amZm9kML1PFyPwr2amZk9kML1vFyPwr2amZk9kML1PK1H4T2amZk9kML1vK1H4T2amZk9kML1vJDC9b2amZm9kML1PJDC9b2amZm9kML1vK1H4T2amZm9kML1PK1H4T2amZm9kML1vK1H4T2amZm9CtcjvK1H4T3rUTg9kML1vK1H4T2amZk9kML1PK1H4T2amZk9CtcjPK1H4T3rUTg9CtcjPK1H4T3rUTi9CtcjvK1H4T3rUTi9kML1PK1H4T2amZm9kML1vJDC9b3NzMw8kML1vFyPwr2amZk9kML1PJDC9b3NzMw8kML1PFyPwr2amZk9kML1vJDC9b2amZm9kML1vJDC9b3NzMw8kML1PJDC9b2amZm9kML1PJDC9b3NzMw8CtcjPOtRuL2wyJI8CtcjPOtRuL3rUTi9kML1POtRuL2wyJI8kML1POtRuL3rUTi9CtcjvArXoz3rUTg9CtcjvIaWnL3rUTg9CtcjvArXoz3rUTi9CtcjvOtRuL2wyJI8CtcjvOtRuL3rUTi9CtcjPIaWnL3rUTg9CtcjPArXoz3rUTg9CtcjPOtRuL2wyJI8CtcjPArXoz3rUTi9CtcjPOtRuL3rUTi9CtcjvK1H4T3rUTi9CtcjPK1H4T3rUTi93kEevKKU5j3rUTi93kEePKKU5j3rUTi9vOMNvB+F6z3rUTi9vOMNPB+F6z3rUTi9a7TnO/TC7z3rUTi9a7Tnu/TC7z3rUTi9CtejuyYE8z3rUTi9CtejOyYE8z3rUTi9oZ4pu+kP9T3rUTi9oZ4pO+kP9T3rUTi9AAAAAJDC9T3rUTi9a7Tnu/TC7z3rUTg9a7Tnu/TC7z3rUTi9CtejuyYE8z3rUTg9CtejuyYE8z3rUTi9vOMNPB+F6z3rUTg9a7TnO/TC7z3rUTg9vOMNPB+F6z3rUTi9a7TnO/TC7z3rUTi9CtcjPK1H4T3rUTg9CtcjvK1H4T3rUTg93kEePKKU5j3rUTg93kEevKKU5j3rUTg9vOMNPB+F6z3rUTg9vOMNvB+F6z3rUTg9a7TnO/TC7z3rUTg9a7Tnu/TC7z3rUTg9CtejOyYE8z3rUTg9CtejuyYE8z3rUTg9oZ4pO+kP9T3rUTg9oZ4pu+kP9T3rUTg9AAAAAJDC9T3rUTg9a7Tnu/TC7z3rUTg9vOMNvB+F6z3rUTg9a7Tnu/TC7z3rUTi9vOMNvB+F6z3rUTi93kEevKKU5j3rUTg9CtcjvK1H4T3rUTg93kEevKKU5j3rUTi9CtcjvK1H4T3rUTi9AAAAAJDC9T3rUTg9AAAAAJDC9T3rUTi9oZ4pO+kP9T3rUTg9oZ4pO+kP9T3rUTi9oZ4pO+kP9T3rUTg9oZ4pO+kP9T3rUTi9CtejOyYE8z3rUTg9CtejOyYE8z3rUTi93kEePKKU5j3rUTg9vOMNPB+F6z3rUTg93kEePKKU5j3rUTi9vOMNPB+F6z3rUTi9CtcjPK1H4T3rUTg93kEePKKU5j3rUTg9CtcjPK1H4T3rUTi93kEePKKU5j3rUTi9CtejOyYE8z3rUTg9CtejOyYE8z3rUTi9a7TnO/TC7z3rUTg9a7TnO/TC7z3rUTi9vOMNvB+F6z3rUTg93kEevKKU5j3rUTg9vOMNvB+F6z3rUTi93kEevKKU5j3rUTi9CtejuyYE8z3rUTg9CtejuyYE8z3rUTi9oZ4pu+kP9T3rUTg9oZ4pu+kP9T3rUTi9oZ4pu+kP9T3rUTg9oZ4pu+kP9T3rUTi9AAAAAJDC9T3rUTg9AAAAAJDC9T3rUTi9qar//wAAAICpqv//AAAAgKmq//8AAACAqar//wAAAICpqv//AAAAgKmq//8AAACAqar//wAAAICpqv//AAAAgP9///8AAACA/3///wAAAID/f///AAAAgP9///8AAACA/38AAAAAAID/fwAAAAAAgP9/AAAAAACA/38AAAAAAID/f/9/AAAAgP9//38AAACA/3//fwAAAID/f/9/AAAAgP9/AAAAAACA/38AAAAAAID/fwAAAAAAgP9/AAAAAACA/3//fwAAAID/f/9/AAAAgP9//38AAACA/3//fwAAAID/////AAAAgP////8AAACA/////wAAAID/////AAAAgP////8AAACA/////wAAAID/////AAAAgP////8AAACAAAD/fwAAAIAAAP9/AAAAgAAA/38AAACAAAD/fwAAAIAAAP9/AAAAgAAA/38AAACAAAD/fwAAAIAAAP9/AAAAgAAA/38AAACAAAD/fwAAAID///9/AAAAgP///38AAACA////fwAAAID///9/AAAAgP///38AAACA////fwAAAID///9/AAAAgP///38AAACA////fwAAAID///9/AAAAgP9//38AAACA/3//fwAAAID/f/9/AAAAgP9//38AAACA/////wAAAID/////AAAAgP////8AAACA/////wAAAID/f///AAAAgP9///8AAACA/3///wAAAID/f///AAAAgP9///8AAACA/3///wAAAID/f///AAAAgP9///8AAACA/3+qKgAAAID/f6oqAAAAgP9/qioAAACA/3+qKgAAAID/fwAAAAAAgP9/AAAAAACA/38AAAAAAID/fwAAAAAAgP9///8AAACA/3///wAAAID/f///AAAAgP9///8AAACAAAD/f/9//78AAP9//3//vwAA/3//f/+/AAD/f/9//78AAP9//3//v////3/+////////f/////////9//v///////3//////////f///////////AAAAgP////8AAACA/////wAAAID/////AAAAgP////8AAACA/////wAAAID/////AAAAgP////8AAACA/////wAAAID/////AAAAgP////8AAACA/////wAAAID/////AAAAgP8//78AAACA/z//vwAAAIAlUSXRAAAAgCVRJdEAAACAJdHZrgAAAID/v/+/AAAAgCXR2a4AAACA/7//vwAAAID/f/9/AAAAgP9//38AAACA/3//fwAAAID/f/9/AAAAgP9//38AAACA/3//fwAAAID/f/9/AAAAgP9//38AAACA/3//fwAAAID/f/9/AAAAgP9//38AAACA/3//fwAAAID/f/9/AAAAgP8//78AAACA2S7ZrgAAAID/P/+/AAAAgNku2a4AAACADBsMmwAAAIDkDuOOAAAAgAwbDJsAAACA5A7jjgAAAID/f///AAAAgP9///8AAACADJvy5AAAAIAMm/LkAAAAgAyb8uQAAACADJvy5AAAAIDZriXRAAAAgNmuJdEAAACA8uQMmwAAAIAl0dmuAAAAgPLkDJsAAACAJdHZrgAAAIAa8eOOAAAAgPLkDJsAAACAGvHjjgAAAIDy5AybAAAAgNmuJdEAAACA2a4l0QAAAID/v/+/AAAAgP+//78AAACA2S7ZrgAAAIAMGwybAAAAgNku2a4AAACADBsMmwAAAIAlUSXRAAAAgCVRJdEAAACA8mTy5AAAAIDyZPLkAAAAgPJk8uQAAACA8mTy5AAAAID/f///AAAAgP9///8AAACA")
|
||||||
|
}, {
|
||||||
|
"aabb": AABB(-0.03, -0.12, -0.075, 0.06, 0.24, 0.15),
|
||||||
|
"attribute_data": PackedByteArray("XS6XP0T3Qj9dLpc/dxH6PyaTyT5E90I/JpPJPncR+j8mk8m+RPdCPyaTyb53Efo/XS6Xv0T3Qj9dLpe/dxH6P10ul7+US9o/XS6XvxaLRb8mk8m+lEvaPyaTyb4Wi0W/JpPJvhaLRb8mk8m+xmIxQF0ul78Wi0W/XS6Xv8ZiMUBdLpc/xmKRQCaTyT7GYpFAXS6XPyaTCcAmk8k+JpMJwF0ulz8Wi0W/XS6XP8ZiMUAmk8k+FotFvyaTyT7GYjFAJpPJvsZikUBdLpe/xmKRQCaTyb4mkwnAXS6XvyaTCcBdLpc/hlOAQCaTyT6GU4BAXS6XPyaTCcAmk8k+JpMJwCaTyb6GU4BAXS6Xv4ZTgEAmk8m+JpMJwF0ul78mkwnA9Pk8QF6vl0CLxeI/JpMJwPT5PEBUKlXA9Pk8wFQqVcCLxeK/JpMJwIvF4r/GYpFAi8XiP4ZTgEDw93s/XS63QCmXND/GYpFA9Pk8wF0ut0D0+TzAVCpVwIvF4r+GU4BA9Pk8wF6vl0Dw93u/XS63QCmXNL/GYpFA9Pk8QF0ut0CLxeI/xmKRQIvF4j8mkwnAi8XivyaTCcD0+TxAVCpVwF0ulz9er5dAXS6Xv16vl0BdLpc/VCpVwF0ul79UKlXAXS6XP10ut0BdLpe/XS63QF0ulz9UKlXAXS6Xv1QqVcBdLpe/6PP5vyaTyb7GYjFAXS6Xv/T5fEBdLpc/9Pl8QCaTyT7GYjFAJpPJPhaLRb8mk8m+FotFv10ulz/o8/m/XS6Xv+3gDkBdLpe/QIgBPV0ulz/t4A5AXS6XP0CIAT1dLpc/6PP5v10ulz/4+/0/XS6Xv+jz+b9dLpe/+Pv9PyaTyT6US9o/JpPJPhaLRb9dLpc/lEvaP10ulz8Wi0W/i8XiPyaTCcCLxeI/hlOAQIvF4r8mkwnAKZc0P8ZikUCLxeK/xmKRQIvF4r+GU4BAi8XivyaTCcAplzS/xmKRQIvF4j8mkwnAi8XiP8ZikUAmk8k+VCpVwCaTyb5UKlXA0bTCPtCvW8DRtMK+0K9bwKORrj6Iw2HAo5GuvojDYcDwiI6+cvtmwPCIjj5y+2bAJpNJPor8asAmk0m+ivxqwIOv0D3ugG3Ag6/Qve6AbcDxsKoOulxuwIvF4j+g4Mq/i8Xiv6Dgyr+LxeI/agjYv4vF4r9qCNi/i8Xiv+mZGMCLxeK/zS0fwIvF4j/pmRjAi8XiP80tH8Amk8k+VCpVwCaTyb5UKlXA0bTCPtCvW8DRtMK+0K9bwKORrj6Iw2HAo5GuvojDYcDwiI4+cvtmwPCIjr5y+2bAJpNJPor8asAmk0m+ivxqwIOv0D3ugG3Ag6/Qve6AbcAJafYNulxuwIvF4j/NLR/Ai8XiP+mZGMCLxeK/zS0fwIvF4r/pmRjAi8XiP0AVVsCLxeI/XIFPwIvF4r9AFVbAi8Xiv1yBT8CLxeK/QEXEPovF4j9ARcQ+i8Xiv2Dk+D6LxeI/YOT4PovF4r/4azW/i8XiP/hrNb+LxeK/aBwbv4vF4j9oHBu/i8Xiv0/HPMCLxeK/MltDwIvF4j9PxzzAi8XiPzJbQ8CLxeK/XIFPwIvF4r9AFVbAi8XiP1yBT8CLxeI/QBVWwIvF4r9qCNi/i8XiP2oI2L+LxeK/oODKv4vF4j+g4Mq/i8XiPzJbQ8CLxeI/T8c8wIvF4r8yW0PAi8Xiv0/HPMCLxeI/aBwbv4vF4r9oHBu/i8XiP/hrNb+LxeK/+Gs1v4vF4j9g5Pg+i8Xiv2Dk+D6LxeI/QEXEPovF4r9ARcQ+"),
|
||||||
|
"format": 34359742487,
|
||||||
|
"index_count": 138,
|
||||||
|
"index_data": PackedByteArray("YABeAF8AXwBhAGAAYQBiAGAAYQBjAGIAYwBkAGIAZABlAGIAZABmAGUAZABnAGYAZwBoAGYAZwBpAGgAaQBqAGgAbQBrAGwAbABuAG0AcQBvAHAAcAByAHEAdQBzAHQAdAB2AHUAdgB3AHUAdgB4AHcAeAB5AHcAeAB6AHkAegB7AHkAegB8AHsAfAB9AHsAfAB+AH0AfgB/AH0AggCAAIEAgQCDAIIAhgCEAIUAhQCHAIYAigCIAIkAiQCLAIoAjgCMAI0AjQCPAI4AkgCQAJEAkQCTAJIAlgCUAJUAlQCXAJYAmgCYAJkAmQCbAJoAngCcAJ0AnQCfAJ4AogCgAKEAoQCjAKIApgCkAKUApQCnAKYA"),
|
||||||
|
"material": SubResource("StandardMaterial3D_bfdxb"),
|
||||||
|
"name": "yellow",
|
||||||
|
"primitive": 3,
|
||||||
|
"uv_scale": Vector4(0, 0, 0, 0),
|
||||||
|
"vertex_count": 168,
|
||||||
|
"vertex_data": PackedByteArray("kML1vIaWnL3rUTg9kML1vOtRuL2wyJI8CtcjvIaWnL3rUTg9CtcjvOtRuL2wyJI8CtcjPIaWnL3rUTg9CtcjPOtRuL2wyJI8kML1PIaWnL3rUTg9kML1POtRuL2wyJI8kML1vOtRuL2wyJI8kML1vOtRuL3rUTi9CtcjvOtRuL2wyJI8CtcjvOtRuL3rUTi9CtcjPArXoz3rUTi9CtcjPArXoz3rUTg9kML1PArXoz3rUTi9kML1PArXoz3rUTg9kML1POtRuL3rUTi9CtcjPOtRuL3rUTi9kML1PArXoz3rUTi9CtcjPArXoz3rUTi9kML1vArXoz3rUTi9kML1vArXoz3rUTg9CtcjvArXoz3rUTi9CtcjvArXoz3rUTg9CtcjvOtRuL3rUTi9kML1vOtRuL3rUTi9CtcjvArXoz3rUTi9kML1vArXoz3rUTi9kML1vIaWnL3rUTg9CtcjvIaWnL3rUTg9kML1vArXoz3rUTg9CtcjvArXoz3rUTg9CtcjPIaWnL3rUTg9kML1PIaWnL3rUTg9CtcjPArXoz3rUTg9kML1PArXoz3rUTg9kML1vFyPwr2amZk9kML1vArXoz3rUTg9kML1vK1H4T2amZk9kML1vK1H4T2amZm9kML1vArXoz3rUTi9kML1vOtRuL3rUTi9kML1vIaWnL3rUTg9kML1vJDC9b3NzMw8kML1vOtRuL2wyJI8kML1vJDC9b2amZm9kML1PK1H4T2amZk9kML1PIaWnL3rUTg9kML1PFyPwr2amZk9kML1PJDC9b3NzMw8kML1POtRuL2wyJI8kML1PJDC9b2amZm9kML1POtRuL3rUTi9kML1PArXoz3rUTi9kML1PArXoz3rUTg9kML1PK1H4T2amZm9kML1PFyPwr2amZk9kML1vFyPwr2amZk9kML1PK1H4T2amZk9kML1vK1H4T2amZk9kML1vJDC9b2amZm9kML1PJDC9b2amZm9kML1vK1H4T2amZm9kML1PK1H4T2amZm9kML1vK1H4T2amZm9CtcjvK1H4T3rUTg9kML1vK1H4T2amZk9kML1PK1H4T2amZk9CtcjPK1H4T3rUTg9CtcjPK1H4T3rUTi9CtcjvK1H4T3rUTi9kML1PK1H4T2amZm9kML1vJDC9b3NzMw8kML1vFyPwr2amZk9kML1PJDC9b3NzMw8kML1PFyPwr2amZk9kML1vJDC9b2amZm9kML1vJDC9b3NzMw8kML1PJDC9b2amZm9kML1PJDC9b3NzMw8CtcjPOtRuL2wyJI8CtcjPOtRuL3rUTi9kML1POtRuL2wyJI8kML1POtRuL3rUTi9CtcjvArXoz3rUTg9CtcjvIaWnL3rUTg9CtcjvArXoz3rUTi9CtcjvOtRuL2wyJI8CtcjvOtRuL3rUTi9CtcjPIaWnL3rUTg9CtcjPArXoz3rUTg9CtcjPOtRuL2wyJI8CtcjPArXoz3rUTi9CtcjPOtRuL3rUTi9CtcjvK1H4T3rUTi9CtcjPK1H4T3rUTi93kEevKKU5j3rUTi93kEePKKU5j3rUTi9vOMNvB+F6z3rUTi9vOMNPB+F6z3rUTi9a7TnO/TC7z3rUTi9a7Tnu/TC7z3rUTi9CtejuyYE8z3rUTi9CtejOyYE8z3rUTi9oZ4pu+kP9T3rUTi9oZ4pO+kP9T3rUTi9AAAAAJDC9T3rUTi9a7Tnu/TC7z3rUTg9a7Tnu/TC7z3rUTi9CtejuyYE8z3rUTg9CtejuyYE8z3rUTi9vOMNPB+F6z3rUTg9a7TnO/TC7z3rUTg9vOMNPB+F6z3rUTi9a7TnO/TC7z3rUTi9CtcjPK1H4T3rUTg9CtcjvK1H4T3rUTg93kEePKKU5j3rUTg93kEevKKU5j3rUTg9vOMNPB+F6z3rUTg9vOMNvB+F6z3rUTg9a7TnO/TC7z3rUTg9a7Tnu/TC7z3rUTg9CtejOyYE8z3rUTg9CtejuyYE8z3rUTg9oZ4pO+kP9T3rUTg9oZ4pu+kP9T3rUTg9AAAAAJDC9T3rUTg9a7Tnu/TC7z3rUTg9vOMNvB+F6z3rUTg9a7Tnu/TC7z3rUTi9vOMNvB+F6z3rUTi93kEevKKU5j3rUTg9CtcjvK1H4T3rUTg93kEevKKU5j3rUTi9CtcjvK1H4T3rUTi9AAAAAJDC9T3rUTg9AAAAAJDC9T3rUTi9oZ4pO+kP9T3rUTg9oZ4pO+kP9T3rUTi9oZ4pO+kP9T3rUTg9oZ4pO+kP9T3rUTi9CtejOyYE8z3rUTg9CtejOyYE8z3rUTi93kEePKKU5j3rUTg9vOMNPB+F6z3rUTg93kEePKKU5j3rUTi9vOMNPB+F6z3rUTi9CtcjPK1H4T3rUTg93kEePKKU5j3rUTg9CtcjPK1H4T3rUTi93kEePKKU5j3rUTi9CtejOyYE8z3rUTg9CtejOyYE8z3rUTi9a7TnO/TC7z3rUTg9a7TnO/TC7z3rUTi9vOMNvB+F6z3rUTg93kEevKKU5j3rUTg9vOMNvB+F6z3rUTi93kEevKKU5j3rUTi9CtejuyYE8z3rUTg9CtejuyYE8z3rUTi9oZ4pu+kP9T3rUTg9oZ4pu+kP9T3rUTi9oZ4pu+kP9T3rUTg9oZ4pu+kP9T3rUTi9AAAAAJDC9T3rUTg9AAAAAJDC9T3rUTi9qar//wAAAICpqv//AAAAgKmq//8AAACAqar//wAAAICpqv//AAAAgKmq//8AAACAqar//wAAAICpqv//AAAAgP9///8AAACA/3///wAAAID/f///AAAAgP9///8AAACA/38AAAAAAID/fwAAAAAAgP9/AAAAAACA/38AAAAAAID/f/9/AAAAgP9//38AAACA/3//fwAAAID/f/9/AAAAgP9/AAAAAACA/38AAAAAAID/fwAAAAAAgP9/AAAAAACA/3//fwAAAID/f/9/AAAAgP9//38AAACA/3//fwAAAID/////AAAAgP////8AAACA/////wAAAID/////AAAAgP////8AAACA/////wAAAID/////AAAAgP////8AAACAAAD/fwAAAIAAAP9/AAAAgAAA/38AAACAAAD/fwAAAIAAAP9/AAAAgAAA/38AAACAAAD/fwAAAIAAAP9/AAAAgAAA/38AAACAAAD/fwAAAID///9/AAAAgP///38AAACA////fwAAAID///9/AAAAgP///38AAACA////fwAAAID///9/AAAAgP///38AAACA////fwAAAID///9/AAAAgP9//38AAACA/3//fwAAAID/f/9/AAAAgP9//38AAACA/////wAAAID/////AAAAgP////8AAACA/////wAAAID/f///AAAAgP9///8AAACA/3///wAAAID/f///AAAAgP9///8AAACA/3///wAAAID/f///AAAAgP9///8AAACA/3+qKgAAAID/f6oqAAAAgP9/qioAAACA/3+qKgAAAID/fwAAAAAAgP9/AAAAAACA/38AAAAAAID/fwAAAAAAgP9///8AAACA/3///wAAAID/f///AAAAgP9///8AAACAAAD/fwAAAIAAAP9/AAAAgAAA/38AAACAAAD/fwAAAIAAAP9/AAAAgP///38AAACA////fwAAAID///9/AAAAgP///38AAACA////fwAAAID/////AAD/v/////8AAP+//////wAA/7//////AAD/v/////8AAP+//////wAA/7//////AAD/v/////8AAP+//////wAA/7//////AAD/v/////8AAP+//////wAA/7//////AAD/v/8//7//f/+//z//v/9//78lUSXR/3//vyVRJdH/f/+/JdHZrv//////v/+//////yXR2a7//////7//v///////f/9/////v/9//3////+//3//f////7//f/9/////v/9//3////+//3//f////7//f/9/////v/9//3////+//3//f////7//f/9/////v/9//3////+//3//f////7//f/9/////v/8//7//f/+/2S7Zrv9//7//P/+//3//v9ku2a7/f/+/DBsMm/9//7/kDuOO/3//vwwbDJv/f/+/5A7jjv9//7//f/////////9/////////DJvy5P////8Mm/Lk/////wyb8uT/////DJvy5P/////ZriXR/////9muJdH/////8uQMm/////8l0dmu//////LkDJv/////JdHZrv////8a8eOO//////LkDJv/////GvHjjv/////y5Ayb/////9muJdH/////2a4l0f//////v/+///////+//7//////2S7Zrv9//78MGwyb/3//v9ku2a7/f/+/DBsMm/9//78lUSXR/3//vyVRJdH/f/+/8mTy5P9//7/yZPLk/3//v/Jk8uT/f/+/8mTy5P9//7//f////3//v/9/////f/+/")
|
||||||
|
}]
|
||||||
|
blend_shape_mode = 0
|
||||||
|
shadow_mesh = SubResource("ArrayMesh_j3k8o")
|
||||||
|
|
||||||
|
[sub_resource type="ConvexPolygonShape3D" id="ConvexPolygonShape3D_p04et"]
|
||||||
|
points = PackedVector3Array(0.03, 0.109992, 0.075, 0.00258418, 0.119648, 0.0449883, 0, 0.12, 0.0449883, -0.03, 0.109992, 0.075, 0.03, -0.0950039, 0.075, 0.03, 0.109992, -0.075, 0.00258418, 0.119648, -0.0450029, 0, 0.12, -0.0450029, -0.00259006, 0.119648, 0.0449883, -0.03, 0.109992, -0.075, -0.03, -0.0950039, 0.075, 0.03, -0.12, 0.0249902, 0.03, -0.12, -0.075, -0.00259006, 0.119648, -0.0450029, -0.03, -0.12, -0.075, -0.03, -0.12, 0.0249902)
|
||||||
|
|
||||||
|
[node name="blasterN_Clip" type="RigidBody3D"]
|
||||||
|
collision_layer = 8
|
||||||
|
collision_mask = 5
|
||||||
|
script = ExtResource("1_d1wy0")
|
||||||
|
weapon = SubResource("Resource_8ete7")
|
||||||
|
TYPE = "Ammo"
|
||||||
|
|
||||||
|
[node name="clipA2" type="MeshInstance3D" parent="."]
|
||||||
|
mesh = SubResource("ArrayMesh_py3xv")
|
||||||
|
skeleton = NodePath("")
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
|
||||||
|
shape = SubResource("ConvexPolygonShape3D_p04et")
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
[gd_scene load_steps=2 format=3 uid="uid://dc48o4niy1mok"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://b26eegme16mfw" path="res://client/template/scripts/Projectiles/Projectile.gd" id="1_epqi3"]
|
||||||
|
|
||||||
|
[node name="Projectile" type="Node3D"]
|
||||||
|
script = ExtResource("1_epqi3")
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
[gd_scene load_steps=3 format=3 uid="uid://bpxa3je174q43"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://b26eegme16mfw" path="res://client/template/scripts/Projectiles/Projectile.gd" id="1_won33"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://dxlkgbr1p580" path="res://client/template/Spawnable_Objects/bullet.tscn" id="2_sq5da"]
|
||||||
|
|
||||||
|
[node name="Projectile" type="Node3D"]
|
||||||
|
script = ExtResource("1_won33")
|
||||||
|
Projectile_Type = "Rigidbody_Projectile"
|
||||||
|
Projectile_Velocity = 20
|
||||||
|
Rigid_Body_Projectile = ExtResource("2_sq5da")
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 990 B |
@@ -0,0 +1,14 @@
|
|||||||
|
[gd_scene load_steps=3 format=3 uid="uid://6rfh1ejt4m6m"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://bfn8eu00l4btq" path="res://client/template/scripts/Projectiles/melee_weapon_projectile.gd" id="1_qlmbe"]
|
||||||
|
|
||||||
|
[sub_resource type="BoxShape3D" id="BoxShape3D_q86ac"]
|
||||||
|
|
||||||
|
[node name="MeleeProjectile" type="Node3D"]
|
||||||
|
script = ExtResource("1_qlmbe")
|
||||||
|
Projectile_Type = "over_ride"
|
||||||
|
|
||||||
|
[node name="MeleeHitbox" type="ShapeCast3D" parent="."]
|
||||||
|
shape = SubResource("BoxShape3D_q86ac")
|
||||||
|
target_position = Vector3(0, 0, -1)
|
||||||
|
collision_mask = 37
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
[gd_scene load_steps=4 format=3 uid="uid://ddfiivxgnakti"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://biivm72fp7af8" path="res://client/template/scripts/Projectiles/rocket_launcher_projectile.gd" id="1_dkmt1"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://cqhlfy6ccomm3" path="res://client/template/Spawnable_Objects/rocket.tscn" id="2_u24w0"]
|
||||||
|
|
||||||
|
[sub_resource type="SphereShape3D" id="SphereShape3D_wqjlt"]
|
||||||
|
radius = 5.0
|
||||||
|
|
||||||
|
[node name="Projectile" type="Node3D" node_paths=PackedStringArray("explosion")]
|
||||||
|
script = ExtResource("1_dkmt1")
|
||||||
|
explosion = NodePath("ExplosionRadias")
|
||||||
|
Projectile_Type = "Rigidbody_Projectile"
|
||||||
|
Projectile_Velocity = 20
|
||||||
|
Expirey_Time = 20
|
||||||
|
Rigid_Body_Projectile = ExtResource("2_u24w0")
|
||||||
|
pass_through = true
|
||||||
|
|
||||||
|
[node name="ExplosionRadias" type="ShapeCast3D" parent="."]
|
||||||
|
top_level = true
|
||||||
|
shape = SubResource("SphereShape3D_wqjlt")
|
||||||
|
target_position = Vector3(0, 0, 0)
|
||||||
|
collision_mask = 37
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
[gd_scene load_steps=3 format=3 uid="uid://brvfyahytwd8m"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://dnh4a4vkl0cl1" path="res://client/template/scripts/Projectiles/shotgun_projectile.gd" id="1_idx2q"]
|
||||||
|
|
||||||
|
[sub_resource type="Curve2D" id="Curve2D_2lhxk"]
|
||||||
|
_data = {
|
||||||
|
"points": PackedVector2Array(0, 0, 0, 0, 7, 3, 0, 0, 0, 0, -30, -11, 0, 0, 0, 0, -8, -18, 0, 0, 0, 0, 8, -9, -2.50282, -11.0124, 2.50282, 11.0124, 19, 13, 0, 0, 0, 0, -21, 1, 0, 0, 0, 0, 22, 22, 0, 0, 0, 0, 12, 21, 0, 0, 0, 0, -33, 4)
|
||||||
|
}
|
||||||
|
point_count = 9
|
||||||
|
|
||||||
|
[node name="shotgun_projectile" type="Node3D"]
|
||||||
|
script = ExtResource("1_idx2q")
|
||||||
|
Randomness = 2.941
|
||||||
|
Split_Damage = true
|
||||||
|
|
||||||
|
[node name="shotgun_pattern" type="Path2D" parent="."]
|
||||||
|
curve = SubResource("Curve2D_2lhxk")
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
extends Node
|
||||||
|
class_name Spray_Profile
|
||||||
|
|
||||||
|
@export_category("Random_Spray")
|
||||||
|
@export var Spray_Noise: FastNoiseLite
|
||||||
|
@export_range(0.0,10.0) var Random_Spray_Multiplier: float = 1.0
|
||||||
|
@export var Max_Limit: int = 30
|
||||||
|
@export var Updwards_Lock: bool = false
|
||||||
|
@export var True_Random: bool = true
|
||||||
|
|
||||||
|
@export_category("Path_Spray")
|
||||||
|
@export var Spray_Path: Path2D
|
||||||
|
@export_range(0.0,10.0) var Path_Spray_Multiplier: float = 1.0
|
||||||
|
@export_range(0.0,1.0) var Spray_Mix: float = 1.0
|
||||||
|
|
||||||
|
var Random_Spray: Vector2 = Vector2.ZERO
|
||||||
|
var Spray_Vector: Vector2 = Vector2.ZERO
|
||||||
|
|
||||||
|
func Get_Spray(count: int,_max_count: int)->Vector2:
|
||||||
|
if Spray_Noise:
|
||||||
|
if True_Random:
|
||||||
|
Spray_Noise.set_seed(randi())
|
||||||
|
|
||||||
|
var x = Spray_Noise.get_noise_1d(count)*min(count,Max_Limit)
|
||||||
|
var y = Spray_Noise.get_noise_2d(_max_count,count)*min(count,Max_Limit)
|
||||||
|
|
||||||
|
if Updwards_Lock:
|
||||||
|
y = -abs(y)
|
||||||
|
|
||||||
|
Random_Spray = Vector2(x,y)*Random_Spray_Multiplier
|
||||||
|
|
||||||
|
if Spray_Path:
|
||||||
|
var Path_Points: Curve2D = Spray_Path.get_curve()
|
||||||
|
var Point_Count: int = Path_Points.get_point_count()
|
||||||
|
count = min(count-1,Point_Count-1)
|
||||||
|
|
||||||
|
Spray_Vector = Path_Points.get_point_position(count)*Path_Spray_Multiplier
|
||||||
|
|
||||||
|
|
||||||
|
var Spray = Spray_Vector + (Random_Spray*Spray_Mix)
|
||||||
|
return Spray
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://dvcpsronqmkmr
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
[gd_scene load_steps=4 format=3 uid="uid://ciu0xkaw0ioef"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://dvcpsronqmkmr" path="res://client/template/Spawnable_Objects/SprayProfiles/spray_profile.gd" id="1_60v4d"]
|
||||||
|
|
||||||
|
[sub_resource type="FastNoiseLite" id="FastNoiseLite_4msk4"]
|
||||||
|
|
||||||
|
[sub_resource type="Curve2D" id="Curve2D_0vouc"]
|
||||||
|
_data = {
|
||||||
|
"points": PackedVector2Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, -2, 0, 0, 0, 0, 0, -11, 0, 0, 0, 0, 1, -23, 0, 0, 0, 0, 2, -35, 0, 0, 0, 0, -4, -50, 0, 0, 0, 0, -7, -62, 0, 0, 0, 0, -12, -69, 0, 0, 0, 0, -6, -76, 0, 0, 0, 0, 12, -74, 0, 0, 0, 0, 9, -86, 0, 0, 0, 0, 16, -81, 0, 0, 0, 0, 21, -76, 0, 0, 0, 0, 19, -83, 0, 0, 0, 0, 23, -84, 0, 0, 0, 0, 36, -82, 0, 0, 0, 0, 35, -79, 0, 0, 0, 0, 28, -81, 0, 0, 0, 0, 23, -81, 0, 0, 0, 0, 5, -88, 0, 0, 0, 0, 2, -90, 0, 0, 0, 0, -6, -88, 0, 0, 0, 0, -10, -91, 0, 0, 0, 0, -12, -91, 0, 0, 0, 0, -13, -89, 0, 0, 0, 0, -13, -85, 0, 0, 0, 0, -15, -85, 0, 0, 0, 0, -16, -88, 0, 0, 0, 0, -19, -90, 0, 0, 0, 0, -20, -85)
|
||||||
|
}
|
||||||
|
point_count = 30
|
||||||
|
|
||||||
|
[node name="Spray_Profile" type="Node" node_paths=PackedStringArray("Spray_Path")]
|
||||||
|
script = ExtResource("1_60v4d")
|
||||||
|
Spray_Noise = SubResource("FastNoiseLite_4msk4")
|
||||||
|
Spray_Path = NodePath("Path2D")
|
||||||
|
Path_Spray_Multiplier = 0.58
|
||||||
|
|
||||||
|
[node name="Path2D" type="Path2D" parent="."]
|
||||||
|
curve = SubResource("Curve2D_0vouc")
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
[gd_scene load_steps=3 format=3 uid="uid://3mb12hvruajh"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://dvcpsronqmkmr" path="res://client/template/Spawnable_Objects/SprayProfiles/spray_profile.gd" id="1_35g6m"]
|
||||||
|
|
||||||
|
[sub_resource type="FastNoiseLite" id="FastNoiseLite_4msk4"]
|
||||||
|
seed = 145
|
||||||
|
frequency = 0.307
|
||||||
|
cellular_jitter = -1.115
|
||||||
|
cellular_return_type = 0
|
||||||
|
domain_warp_type = 1
|
||||||
|
domain_warp_amplitude = 30.075
|
||||||
|
domain_warp_frequency = -0.835
|
||||||
|
domain_warp_fractal_type = 2
|
||||||
|
domain_warp_fractal_octaves = 1
|
||||||
|
|
||||||
|
[node name="Spray_Profile" type="Node"]
|
||||||
|
script = ExtResource("1_35g6m")
|
||||||
|
Spray_Noise = SubResource("FastNoiseLite_4msk4")
|
||||||
|
Random_Spray_Multiplier = 2.371
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
[gd_scene load_steps=3 format=3 uid="uid://ceuaamuau8pl8"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://dvcpsronqmkmr" path="res://client/template/Spawnable_Objects/SprayProfiles/spray_profile.gd" id="1_hmoot"]
|
||||||
|
|
||||||
|
[sub_resource type="FastNoiseLite" id="FastNoiseLite_4msk4"]
|
||||||
|
seed = 145
|
||||||
|
frequency = 0.307
|
||||||
|
cellular_jitter = -1.115
|
||||||
|
cellular_return_type = 0
|
||||||
|
domain_warp_type = 1
|
||||||
|
domain_warp_amplitude = 30.075
|
||||||
|
domain_warp_frequency = -0.835
|
||||||
|
domain_warp_fractal_type = 2
|
||||||
|
domain_warp_fractal_octaves = 1
|
||||||
|
|
||||||
|
[node name="Spray_Profile" type="Node"]
|
||||||
|
script = ExtResource("1_hmoot")
|
||||||
|
Spray_Noise = SubResource("FastNoiseLite_4msk4")
|
||||||
|
Random_Spray_Multiplier = 10.0
|
||||||
|
Updwards_Lock = true
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,65 @@
|
|||||||
|
[gd_scene load_steps=5 format=4 uid="uid://dxlkgbr1p580"]
|
||||||
|
|
||||||
|
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_bix2d"]
|
||||||
|
radius = 0.099605
|
||||||
|
height = 0.419677
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_x0fj0"]
|
||||||
|
resource_name = "yellow"
|
||||||
|
vertex_color_use_as_albedo = true
|
||||||
|
albedo_color = Color(0.0627451, 0.639216, 0.576471, 1)
|
||||||
|
metallic = 1.0
|
||||||
|
emission_enabled = true
|
||||||
|
emission = Color(0, 0.960784, 0.960784, 1)
|
||||||
|
emission_energy_multiplier = 1.78
|
||||||
|
|
||||||
|
[sub_resource type="ArrayMesh" id="ArrayMesh_ly6dy"]
|
||||||
|
_surfaces = [{
|
||||||
|
"aabb": AABB(-0.01, -0.025, -0.01, 0.02, 0.05, 0.02),
|
||||||
|
"format": 34359742465,
|
||||||
|
"index_count": 276,
|
||||||
|
"index_data": PackedByteArray("AgAAAAEAAQADAAIAAQAEAAMABAAFAAMABAAGAAUABgAHAAUABgAIAAcACAAJAAcACAAKAAkACgALAAkACgAMAAsADAANAAsADAAOAA0ADgAPAA0ADwAQAA0ADwARABAADwASABEAEgATABEAEgAUABMAFAAVABMAFAAWABUAFgAXABUAGQAYAAYABgAEABkAFgAUABoAGgAbABYAHAASAA8ADwAdABwAHgAFAAcABwAfAB4AIAAOAAwADAAhACAAEQATACIAIgAjABEAIQAMAAoACgAkACEAJwAlACYAJgAZACcAJgAoABkAKAAYABkAKAAeABgAHgApABgAHgAfACkAHwAkACkAHwAqACQAKgAhACQAKgArACEAKwAgACEAKwAsACAALAAdACAALAAtAB0ALQAcAB0ALQAjABwAIwAaABwAIwAiABoAIgAbABoAIgAuABsALgAvABsAKwALAA0ADQAsACsALAANABAAEAAtACwAHgAoAAMAAwAFAB4AJgAlAAAAAAACACYAJAAKAAgACAApACQAHwAHAAkACQAqAB8AJQAnAAEAAQAAACUALQAQABEAEQAjAC0AFAASABwAHAAaABQAFwAWABsAGwAvABcAEwAVAC4ALgAiABMAHQAPAA4ADgAgAB0AFQAXAC8ALwAuABUAJwAZAAQABAABACcAKQAIAAYABgAYACkAKAAmAAIAAgADACgAKgAJAAsACwArACoA"),
|
||||||
|
"name": "yellow",
|
||||||
|
"primitive": 3,
|
||||||
|
"uv_scale": Vector4(0, 0, 0, 0),
|
||||||
|
"vertex_count": 48,
|
||||||
|
"vertex_data": PackedByteArray("CtcjvM3MzLwAAACA3kEevM3MzLyhnik73kEevM3MzLyhnim7vOMNvM3MzLwK16O7vOMNvM3MzLwK16M7a7Tnu83MzLxrtOe7a7Tnu83MzLxrtOc7Cteju83MzLy84w28Cteju83MzLy84w08oZ4pu83MzLzeQR68oZ4pu83MzLzeQR48AAAAAM3MzLwK1yO8AAAAAM3MzLwK1yM8oZ4pO83MzLzeQR68oZ4pO83MzLzeQR48CtejO83MzLy84w08CtejO83MzLy84w28a7TnO83MzLxrtOe7a7TnO83MzLxrtOc7vOMNPM3MzLwK16O7vOMNPM3MzLwK16M73kEePM3MzLyhnim73kEePM3MzLyhnik7CtcjPM3MzLwAAACAa7Tnu83MzDxrtOc7vOMNvM3MzDwK16M7vOMNPM3MzDwK16M73kEePM3MzDyhnik7a7TnO83MzDxrtOc7CtejO83MzDy84w08a7Tnu83MzDxrtOe7Cteju83MzDy84w28oZ4pO83MzDzeQR48AAAAAM3MzDwK1yM8vOMNPM3MzDwK16O7a7TnO83MzDxrtOe7oZ4pu83MzDzeQR48CtcjvM3MzDwAAACA3kEevM3MzDyhnim73kEevM3MzDyhnik7vOMNvM3MzDwK16O7Cteju83MzDy84w08oZ4pu83MzDzeQR68AAAAAM3MzDwK1yO8oZ4pO83MzDzeQR68CtejO83MzDy84w283kEePM3MzDyhnim7CtcjPM3MzDwAAACA")
|
||||||
|
}]
|
||||||
|
blend_shape_mode = 0
|
||||||
|
|
||||||
|
[sub_resource type="ArrayMesh" id="ArrayMesh_sqgwv"]
|
||||||
|
resource_name = "foamBulletA_Mesh foamBulletA"
|
||||||
|
_surfaces = [{
|
||||||
|
"aabb": AABB(-0.01, -0.025, -0.01, 0.02, 0.05, 0.02),
|
||||||
|
"attribute_data": PackedByteArray("JpPJPgAAgD/RtMI++AqNP9G0wj4Q6mU/o5GuPjabTT+jka4+ZTKZP/CIjj6Iuzg/8IiOPjyioz8mk0k+LrcoPyaTST5ppKs/g6/QPZilHj+Dr9A9NK2wPwAAAABtNhs/AAAAAMpksj+Dr9C9mKUeP4Ov0L00rbA/JpNJvmmkqz8mk0m+LrcoP/CIjr6Iuzg/8IiOvjyioz+jka6+NptNP6ORrr5lMpk/0bTCvhDqZT/RtMK++AqNPyaTyb4AAIA/gHxSPQACgTyAfFI9+Pv9P4B8Ur0AAoE8gHxSvfj7/T+AfFK9+Pv9P4B8Ur0AAoE8gHxSPfj7/T+AfFI9AAKBPIB8Uj34+/0/gHxSvfj7/T+AfFI9AAKBPIB8Ur0AAoE8gHxSPfj7/T+AfFK9+Pv9P4B8Uj0AAoE8gHxSvQACgTyAfFI9+Pv9P4B8Ur34+/0/gHxSPQACgTyAfFK9AAKBPIB8Ur34+/0/gHxSvQACgTyAfFI9+Pv9P4B8Uj0AAoE8gHxSPfj7/T+AfFK9+Pv9P4B8Uj0AAoE8gHxSvQACgTwmk8m+AACAP9G0wr4Q6mU/0bTCvvgKjT+jka6+ZTKZP6ORrr42m00/8IiOvjyioz/wiI6+iLs4PyaTSb5ppKs/JpNJvi63KD+Dr9C9NK2wP4Ov0L2YpR4/AAAAAMpksj8AAAAAbTYbP4Ov0D00rbA/g6/QPZilHj8mk0k+aaSrPyaTST4utyg/8IiOPjyioz/wiI4+iLs4P6ORrj5lMpk/o5GuPjabTT/RtMI++AqNP9G0wj4Q6mU/JpPJPgAAgD+AfFI9+Pv9P4B8Ur34+/0/gHxSPQACgTyAfFK9AAKBPIB8Uj34+/0/gHxSvfj7/T+AfFI9AAKBPIB8Ur0AAoE8gHxSPQACgTyAfFI9+Pv9P4B8Ur0AAoE8gHxSvfj7/T+AfFI9AAKBPIB8Uj34+/0/gHxSvQACgTyAfFK9+Pv9P4B8Uj34+/0/gHxSvfj7/T+AfFI9AAKBPIB8Ur0AAoE8gHxSPfj7/T+AfFK9+Pv9P4B8Uj0AAoE8gHxSvQACgTyAfFI9AAKBPIB8Uj34+/0/gHxSvQACgTyAfFK9+Pv9P4B8Uj34+/0/gHxSvfj7/T+AfFI9AAKBPIB8Ur0AAoE8gHxSvfj7/T+AfFK9AAKBPIB8Uj34+/0/gHxSPQACgTyAfFK9+Pv9P4B8Ur0AAoE8gHxSPfj7/T+AfFI9AAKBPIB8Ur34+/0/gHxSvQACgTyAfFI9+Pv9P4B8Uj0AAoE8gHxSPfj7/T+AfFK9+Pv9P4B8Uj0AAoE8gHxSvQACgTyAfFK9+Pv9P4B8Ur0AAoE8gHxSPfj7/T+AfFI9AAKBPIB8Uj0AAoE8gHxSPfj7/T+AfFK9AAKBPIB8Ur34+/0/gHxSPfj7/T+AfFK9+Pv9P4B8Uj0AAoE8gHxSvQACgTyAfFI9AAKBPIB8Uj34+/0/gHxSvQACgTyAfFK9+Pv9P4B8Uj34+/0/gHxSvfj7/T+AfFI9AAKBPIB8Ur0AAoE8"),
|
||||||
|
"format": 34359742487,
|
||||||
|
"index_count": 276,
|
||||||
|
"index_data": PackedByteArray("AgAAAAEAAQADAAIAAQAEAAMABAAFAAMABAAGAAUABgAHAAUABgAIAAcACAAJAAcACAAKAAkACgALAAkACgAMAAsADAANAAsADAAOAA0ADgAPAA0ADwAQAA0ADwARABAADwASABEAEgATABEAEgAUABMAFAAVABMAFAAWABUAFgAXABUAGgAYABkAGQAbABoAHgAcAB0AHQAfAB4AIgAgACEAIQAjACIAJgAkACUAJQAnACYAKgAoACkAKQArACoALgAsAC0ALQAvAC4AMgAwADEAMQAzADIANgA0ADUANQA3ADYANQA4ADcAOAA5ADcAOAA6ADkAOgA7ADkAOgA8ADsAPAA9ADsAPAA+AD0APgA/AD0APgBAAD8AQABBAD8AQABCAEEAQgBDAEEAQgBEAEMARABFAEMARABGAEUARgBHAEUARgBIAEcASABJAEcASABKAEkASgBLAEkATgBMAE0ATQBPAE4AUgBQAFEAUQBTAFIAVgBUAFUAVQBXAFYAWgBYAFkAWQBbAFoAXgBcAF0AXQBfAF4AYgBgAGEAYQBjAGIAZgBkAGUAZQBnAGYAagBoAGkAaQBrAGoAbgBsAG0AbQBvAG4AcgBwAHEAcQBzAHIAdgB0AHUAdQB3AHYAegB4AHkAeQB7AHoAfgB8AH0AfQB/AH4AggCAAIEAgQCDAIIAhgCEAIUAhQCHAIYAigCIAIkAiQCLAIoAjgCMAI0AjQCPAI4A"),
|
||||||
|
"material": SubResource("StandardMaterial3D_x0fj0"),
|
||||||
|
"name": "yellow",
|
||||||
|
"primitive": 3,
|
||||||
|
"uv_scale": Vector4(0, 0, 0, 0),
|
||||||
|
"vertex_count": 144,
|
||||||
|
"vertex_data": PackedByteArray("CtcjvM3MzLwAAACA3kEevM3MzLyhnik73kEevM3MzLyhnim7vOMNvM3MzLwK16O7vOMNvM3MzLwK16M7a7Tnu83MzLxrtOe7a7Tnu83MzLxrtOc7Cteju83MzLy84w28Cteju83MzLy84w08oZ4pu83MzLzeQR68oZ4pu83MzLzeQR48AAAAAM3MzLwK1yO8AAAAAM3MzLwK1yM8oZ4pO83MzLzeQR68oZ4pO83MzLzeQR48CtejO83MzLy84w08CtejO83MzLy84w28a7TnO83MzLxrtOe7a7TnO83MzLxrtOc7vOMNPM3MzLwK16O7vOMNPM3MzLwK16M73kEePM3MzLyhnim73kEePM3MzLyhnik7CtcjPM3MzLwAAACAa7Tnu83MzDxrtOc7a7Tnu83MzLxrtOc7vOMNvM3MzDwK16M7vOMNvM3MzLwK16M7vOMNPM3MzLwK16M7vOMNPM3MzDwK16M73kEePM3MzLyhnik73kEePM3MzDyhnik7a7TnO83MzLxrtOc7CtejO83MzLy84w08a7TnO83MzDxrtOc7CtejO83MzDy84w08a7Tnu83MzLxrtOe7Cteju83MzLy84w28a7Tnu83MzDxrtOe7Cteju83MzDy84w28oZ4pO83MzLzeQR48AAAAAM3MzLwK1yM8oZ4pO83MzDzeQR48AAAAAM3MzDwK1yM8vOMNPM3MzLwK16O7vOMNPM3MzDwK16O7a7TnO83MzLxrtOe7a7TnO83MzDxrtOe7AAAAAM3MzLwK1yM8oZ4pu83MzLzeQR48AAAAAM3MzDwK1yM8oZ4pu83MzDzeQR48CtcjvM3MzDwAAACA3kEevM3MzDyhnim73kEevM3MzDyhnik7vOMNvM3MzDwK16M7vOMNvM3MzDwK16O7a7Tnu83MzDxrtOc7a7Tnu83MzDxrtOe7Cteju83MzDy84w08Cteju83MzDy84w28oZ4pu83MzDzeQR48oZ4pu83MzDzeQR68AAAAAM3MzDwK1yM8AAAAAM3MzDwK1yO8oZ4pO83MzDzeQR48oZ4pO83MzDzeQR68CtejO83MzDy84w08CtejO83MzDy84w28a7TnO83MzDxrtOc7a7TnO83MzDxrtOe7vOMNPM3MzDwK16M7vOMNPM3MzDwK16O73kEePM3MzDyhnik73kEePM3MzDyhnim7CtcjPM3MzDwAAACAAAAAAM3MzLwK1yO8oZ4pO83MzLzeQR68AAAAAM3MzDwK1yO8oZ4pO83MzDzeQR68oZ4pO83MzLzeQR68CtejO83MzLy84w28oZ4pO83MzDzeQR68CtejO83MzDy84w28vOMNvM3MzDwK16O7vOMNvM3MzLwK16O7a7Tnu83MzDxrtOe7a7Tnu83MzLxrtOe7CtcjvM3MzDwAAACACtcjvM3MzLwAAACA3kEevM3MzDyhnim73kEevM3MzLyhnim7oZ4pu83MzLzeQR48Cteju83MzLy84w08oZ4pu83MzDzeQR48Cteju83MzDy84w08Cteju83MzLy84w28oZ4pu83MzLzeQR68Cteju83MzDy84w28oZ4pu83MzDzeQR683kEevM3MzDyhnik73kEevM3MzLyhnik7CtcjvM3MzDwAAACACtcjvM3MzLwAAACACtejO83MzLy84w28a7TnO83MzLxrtOe7CtejO83MzDy84w28a7TnO83MzDxrtOe7a7TnO83MzLxrtOc7a7TnO83MzDxrtOc7vOMNPM3MzLwK16M7vOMNPM3MzDwK16M73kEePM3MzLyhnik73kEePM3MzDyhnik7CtcjPM3MzLwAAACACtcjPM3MzDwAAACA3kEePM3MzLyhnim73kEePM3MzDyhnim7vOMNPM3MzLwK16O7vOMNPM3MzDwK16O7CtejO83MzLy84w08oZ4pO83MzLzeQR48CtejO83MzDy84w08oZ4pO83MzDzeQR48CtcjPM3MzLwAAACACtcjPM3MzDwAAACA3kEePM3MzLyhnim73kEePM3MzDyhnim7vOMNvM3MzDwK16M7vOMNvM3MzLwK16M73kEevM3MzDyhnik73kEevM3MzLyhnik7Cteju83MzLy84w08a7Tnu83MzLxrtOc7Cteju83MzDy84w08a7Tnu83MzDxrtOc73kEevM3MzDyhnim73kEevM3MzLyhnim7vOMNvM3MzDwK16O7vOMNvM3MzLwK16O7oZ4pu83MzLzeQR68AAAAAM3MzLwK1yO8oZ4pu83MzDzeQR68AAAAAM3MzDwK1yO8/38AAAAA/7//fwAAAAD/v/9/AAAAAP+//38AAAAA/7//fwAAAAD/v/9/AAAAAP+//38AAAAA/7//fwAAAAD/v/9/AAAAAP+//38AAAAA/7//fwAAAAD/v/9/AAAAAP+//38AAAAA/7//fwAAAAD/v/9/AAAAAP+//38AAAAA/7//fwAAAAD/v/9/AAAAAP+//38AAAAA/7//fwAAAAD/v/9/AAAAAP+//38AAAAA/7//fwAAAAD/v/9/AAAAAP+//z//f/+//7//P/9//7//v9ku/3/Zrv+/2S7/f9mu/78l0f9///+S6CXR/3///5Lo8uT/f///ePLy5P9///948v+//3/////f2a7/f///bNf/v/9/////39mu/3///2zXAAD/v/8//78AACXR2S7/vwAA/7//P/+/AAAl0dku/78Mm/9///+Fzf9//3////+/DJv/f///hc3/f/9/////v///2a4AAJLo///ZrgAAkuj///+/AAD/3////78AAP/f/3//f////7/yZP9/8uT/v/9//3////+/8mT/f/Lk/7//f///////v/9////+//+//3///////7//f///////v/9///////+//3///////7//f////v//v/9////+//+//3///////7//f///////v/9///////+//3///////7//f///////v/9////+//+//3////7//7//f///////v/9////+//+//3////7//7//f///////v/9///////+//3////7//7//f////v//v/9///////+//3///////7//////AAD/v///8uQAAIXN/////wAA/7////LkAACFzf//8uQAAIXN//8l0QAAbNf///LkAACFzf//JdEAAGzXAADZriVR/78AANmuJVH/vwAA/7//P/+/AAD/v/8//78AAP9//3//vwAA/3//f/+/AAAMm/Jk/78AAAyb8mT/v/Jk/3/y5P+/JVH/fyXR/7/yZP9/8uT/vyVR/38l0f+/AAAl0dku/78AAPLkDBv/vwAAJdHZLv+/AADy5Awb/78MG/9/DJv/vwwb/38Mm/+/AAD/f/9//78AAP9//3//v///JdEAAGzX////vwAA/9///yXRAABs1////78AAP/f/7//f////9//v/9/////3yXR/3///5LoJdH/f///kujy5P9///948vLk/3///3jy////f/////////9/////////DJsAAHjy//8MmwAAePL//9muAACS6P//2a4AAJLo2a7/f///bNcMm/9///+Fzdmu/3///2zXDJv/f///hc3///9//////////3////////8MmwAAePL//wybAAB48tku/3/Zrv+/2S7/f9mu/78MG/9/DJv/vwwb/38Mm/+/JVH/fyXR/7//P/9//7//vyVR/38l0f+//z//f/+//78AAAyb8mT/vwAADJvyZP+/AADZriVR/78AANmuJVH/vwAA8uQMG/+//////wAA/78AAPLkDBv/v/////8AAP+/")
|
||||||
|
}]
|
||||||
|
blend_shape_mode = 0
|
||||||
|
shadow_mesh = SubResource("ArrayMesh_ly6dy")
|
||||||
|
|
||||||
|
[node name="bullet" type="RigidBody3D"]
|
||||||
|
collision_layer = 16
|
||||||
|
collision_mask = 37
|
||||||
|
gravity_scale = 0.0
|
||||||
|
continuous_cd = true
|
||||||
|
contact_monitor = true
|
||||||
|
max_contacts_reported = 5
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 0, 0)
|
||||||
|
shape = SubResource("CapsuleShape3D_bix2d")
|
||||||
|
|
||||||
|
[node name="foamBulletA2" type="MeshInstance3D" parent="."]
|
||||||
|
transform = Transform3D(5, 0, 0, 0, -2.18557e-07, -5, 0, 5, -2.18557e-07, 0, 0, 0)
|
||||||
|
mesh = SubResource("ArrayMesh_sqgwv")
|
||||||
|
skeleton = NodePath("")
|
||||||
|
|
||||||
|
[connection signal="body_entered" from="." to="." method="_on_body_entered"]
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
[gd_scene load_steps=3 format=3 uid="uid://dguqnsdowqt3w"]
|
||||||
|
|
||||||
|
[ext_resource type="Texture2D" uid="uid://clfvflhvcccy1" path="res://client/template/Spawnable_Objects/Projectiles_To_Load/debug_sprite.png" id="1_smdbx"]
|
||||||
|
[ext_resource type="Script" uid="uid://dkt6w5wvebi72" path="res://client/template/scripts/Weapon_State_Machine/hit_debug.gd" id="2_gvqnn"]
|
||||||
|
|
||||||
|
[node name="Node3D" type="Sprite3D"]
|
||||||
|
transform = Transform3D(0.1, 0, 0, 0, 0.1, 0, 0, 0, 0.1, 0, 0, 0)
|
||||||
|
billboard = 2
|
||||||
|
texture = ExtResource("1_smdbx")
|
||||||
|
script = ExtResource("2_gvqnn")
|
||||||
|
|
||||||
|
[node name="Timer" type="Timer" parent="."]
|
||||||
|
autostart = true
|
||||||
|
|
||||||
|
[connection signal="timeout" from="Timer" to="." method="_on_timer_timeout"]
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
[gd_scene load_steps=3 format=3 uid="uid://bj15ogfi1535l"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://dkt6w5wvebi72" path="res://client/template/scripts/Weapon_State_Machine/hit_debug.gd" id="2_w2l74"]
|
||||||
|
|
||||||
|
[sub_resource type="CompressedTexture2D" id="CompressedTexture2D_kr237"]
|
||||||
|
load_path = "res://.godot/imported/crosshair046.png-adf558f9d87ef20104f2ce22346ed1b7.s3tc.ctex"
|
||||||
|
|
||||||
|
[node name="Node3D" type="Sprite3D"]
|
||||||
|
modulate = Color(0, 0, 1, 1)
|
||||||
|
billboard = 2
|
||||||
|
texture = SubResource("CompressedTexture2D_kr237")
|
||||||
|
script = ExtResource("2_w2l74")
|
||||||
|
|
||||||
|
[node name="Timer" type="Timer" parent="."]
|
||||||
|
autostart = true
|
||||||
|
|
||||||
|
[connection signal="timeout" from="Timer" to="." method="_on_timer_timeout"]
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
[gd_scene load_steps=6 format=4 uid="uid://cqhlfy6ccomm3"]
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_030fb"]
|
||||||
|
resource_name = "yellow"
|
||||||
|
albedo_color = Color(0.996078, 0, 0.219608, 1)
|
||||||
|
metallic = 1.0
|
||||||
|
emission_enabled = true
|
||||||
|
emission = Color(1, 0, 0, 1)
|
||||||
|
emission_energy_multiplier = 19.35
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_urtjv"]
|
||||||
|
resource_name = "pink"
|
||||||
|
albedo_color = Color(0.996078, 0.219608, 0.411765, 1)
|
||||||
|
metallic = 1.0
|
||||||
|
|
||||||
|
[sub_resource type="ArrayMesh" id="ArrayMesh_iqbgl"]
|
||||||
|
_surfaces = [{
|
||||||
|
"aabb": AABB(-0.01, -0.03, -0.01, 0.02, 0.06, 0.02),
|
||||||
|
"format": 34896613377,
|
||||||
|
"index_count": 66,
|
||||||
|
"index_data": PackedByteArray("AgAAAAEAAQADAAIAAQAAAAQABAAFAAEABQAEAAYABgAHAAUACAAHAAYABgAJAAgADAAKAAsACwANAAwADgAJAAYABgAKAA4ABgAEAAoABAALAAoABAAAAAsAAAACAAsADwAIAAkACQAOAA8ADwAOAAoACgAMAA8ACwACAAMAAwANAAsA"),
|
||||||
|
"name": "yellow",
|
||||||
|
"primitive": 3,
|
||||||
|
"uv_scale": Vector4(0, 0, 0, 0),
|
||||||
|
"vertex_count": 24,
|
||||||
|
"vertex_data": PackedByteArray("/98AAP/fAAD/31TV/98AAP//AAD/fwAA//9U1f9/AAD/fwAA//8AAP9/VNX//wAA/x8AAP/fAAD/H1TV/98AAAAAVNX/fwAAAAAAAP9/AAD/fwAAAAAAAP/fAAD/HwAA/39U1QAAAAD/31TV/x8AAP8fAAD/HwAA/x9U1f8fAAD/H////38AAP83////NwAA/zf////HAAD/f////98AAP9/////HwAA/8f////HAAD/x////zcAAP/f////fwAA")
|
||||||
|
}, {
|
||||||
|
"aabb": AABB(-0.01, -0.03, -0.01, 0.02, 0.06, 0.02),
|
||||||
|
"format": 34896613377,
|
||||||
|
"index_count": 66,
|
||||||
|
"index_data": PackedByteArray("EgAQABEAEQATABIAEQAUABMAFAAVABMAFAAWABUAFgAXABUAFAAMAA0ADQAWABQAEQAPAAwADAAUABEAEwAFAAcABwASABMAEQAQAAgACAAPABEAEgAHAAgACAAQABIAFQABAAUABQATABUAAwABABUAFQAXAAMADQADABcAFwAWAA0A"),
|
||||||
|
"name": "pink",
|
||||||
|
"primitive": 3,
|
||||||
|
"uv_scale": Vector4(0, 0, 0, 0),
|
||||||
|
"vertex_count": 24,
|
||||||
|
"vertex_data": PackedByteArray("/98AAP/fAAD/31TV/98AAP//AAD/fwAA//9U1f9/AAD/fwAA//8AAP9/VNX//wAA/x8AAP/fAAD/H1TV/98AAAAAVNX/fwAAAAAAAP9/AAD/fwAAAAAAAP/fAAD/HwAA/39U1QAAAAD/31TV/x8AAP8fAAD/HwAA/x9U1f8fAAD/H////38AAP83////NwAA/zf////HAAD/f////98AAP9/////HwAA/8f////HAAD/x////zcAAP/f////fwAA")
|
||||||
|
}]
|
||||||
|
blend_shape_mode = 0
|
||||||
|
|
||||||
|
[sub_resource type="ArrayMesh" id="ArrayMesh_mt61o"]
|
||||||
|
resource_name = "foamBulletB-low_Mesh foamBulletB-low"
|
||||||
|
_surfaces = [{
|
||||||
|
"aabb": AABB(-0.01, -0.03, -0.01, 0.02, 0.06, 0.02),
|
||||||
|
"attribute_data": PackedByteArray("SEP//0hDeYx5qP//eah5jLa8//+FV///trx5jIVXeYx5qP//SEP//3moeYxIQ3mMtrx5jLa8//+FV3mMhVf//3mo//9IQ///eah5jEhDeYz//666/98CzP/fWqn/f5Sj/3/J0f8fWqn/HwLMAACuunmoeYx5qP//SEN5jEhD//+2vP//hVf//7a8eYyFV3mMhVf//4VXeYy2vP//trx5jP8frrr/N6+t/zetx/9/Asz/f1qp/8etx//Hr63/3666eajHkkhDx5Jangh7dlIIe7a8x5KFV8eSiK0Ie6RhCHt5qMeSSEPHklqeCHt2Ugh7Wp4Ie3mox5J2Ugh7SEPHkra8x5KFV8eSiK0Ie6RhCHu2vMeShVfHkoitCHukYQh7SEPHknZSCHt5qMeSWp4Ie4VXx5KkYQh7trzHkoitCHs="),
|
||||||
|
"format": 34896613399,
|
||||||
|
"index_count": 66,
|
||||||
|
"index_data": PackedByteArray("AgAAAAEAAQADAAIABgAEAAUABQAHAAYACgAIAAkACQALAAoADgAMAA0ADQAPAA4AEgAQABEAEQATABIAFgAUABUAFQAXABYAFQAYABcAGAAZABcAGAAaABkAGgAbABkAHgAcAB0AHQAfAB4AIgAgACEAIQAjACIAJgAkACUAJQAnACYA"),
|
||||||
|
"material": SubResource("StandardMaterial3D_030fb"),
|
||||||
|
"name": "yellow",
|
||||||
|
"primitive": 3,
|
||||||
|
"uv_scale": Vector4(0.787402, 4.3622, 0, 0),
|
||||||
|
"vertex_count": 80,
|
||||||
|
"vertex_data": PackedByteArray("/98AAP/f/5//31TV/9//n///AAD/f/+///9U1f9//7//3wAA/9//n/9/AAD//wCA/99U1f/f/5//f1TV//8AgP9/AAD//wCA/x8AAP/f/5//f1TV//8AgP8fVNX/3/+f/x9U1f/f/5//HwAA/9//nwAAVNX/f/+/AAAAAP9//7//fwAAAAD////fAAD/H//f/39U1QAA////31TV/x//3wAAAAD/f////x8AAP/f////HwAA/x////9/AAAAAP///38AAP//////3wAA/x/////fAAD/3/////8AAP9///8AAFTV/3//vwAAAAD/f/+//x9U1f8f/9//HwAA/x//3/8fAAD/H//f/38AAAAA////H1TV/x//3/9/VNUAAP////8AAP9//7///1TV/3//v//fAAD/H//f/99U1f8f/9//H////39U1f83////N1TV/zf////HVNX/f////99U1f9/////H1TV/8f////HVNX/x////zdU1f/f////f1TV/39U1QAA8vj/31TV/x/C6P9/////H/L4/8f///83wuj/H1TV/x/C6P9/VNUAAPL4/zf///83wuj/f////x/y+P9/VNX//5rA/x9U1f/feMb/f////9+awP83////x3jG/x////9/VNUAAFTV/39U1f83////N8Lo/x9U1f8fwuj/H1TV/994xgAAVNX/f1TV/zf////HeMb/H////39U1f/fVNX/33jG/39U1f//msD/x////8d4xv9/////35rA/99U1f/feMb/x////8d4xv//VNX/f1TV/9////9/VNX//1TV/39U1f/f////f1TV/99U1f8fwuj/x////zfC6P9/AAD/fwAA/38AAP9/AAD/fwAA/3////9/AAD/f////3////9/////f////3////9/////f////3////9/////f////38AAP9/////fwAA/3//P/9//z//f/8//3//P/9//z//f/8//3//P/9//z//f////3////9/////f////3////9/////f////3////9/AAD/fwAA/38AAP9/AAD///9/////f////3////9/////f////3////9/////f////3/oougi////f+ii6CLoohbd////f+iiFt3///9/////f+iiFt3///9/6KIW3ZmZZeaZmWXm6KIW3eiiFt3oohbdmZll5uiiFt2ZmWXm6KLoIv///3/oougi////f+ii6CLoougimZmZGZmZmRmZmZkZmZmZGeii6CLoougi")
|
||||||
|
}, {
|
||||||
|
"aabb": AABB(-0.01, -0.03, -0.01, 0.02, 0.06, 0.02),
|
||||||
|
"attribute_data": PackedByteArray("SEP//0hDeYx5qP//eah5jLa8//+FV///trx5jIVXeYx5qP//SEP//3moeYxIQ3mMtrx5jLa8//+FV3mMhVf//3mo//9IQ///eah5jEhDeYz//666/98CzP/fWqn/f5Sj/3/J0f8fWqn/HwLMAACuunmoeYx5qP//SEN5jEhD//+2vP//hVf//7a8eYyFV3mMhVf//4VXeYy2vP//trx5jP8frrr/N6+t/zetx/9/Asz/f1qp/8etx//Hr63/3666eajHkkhDx5Jangh7dlIIe7a8x5KFV8eSiK0Ie6RhCHt5qMeSSEPHklqeCHt2Ugh7Wp4Ie3mox5J2Ugh7SEPHkra8x5KFV8eSiK0Ie6RhCHu2vMeShVfHkoitCHukYQh7SEPHknZSCHt5qMeSWp4Ie4VXx5KkYQh7trzHkoitCHs="),
|
||||||
|
"format": 34896613399,
|
||||||
|
"index_count": 66,
|
||||||
|
"index_data": PackedByteArray("KgAoACkAKQArACoAKQAsACsALAAtACsALAAuAC0ALgAvAC0AMgAwADEAMQAzADIANgA0ADUANQA3ADYAOgA4ADkAOQA7ADoAPgA8AD0APQA/AD4AQgBAAEEAQQBDAEIARgBEAEUARQBHAEYASgBIAEkASQBLAEoATgBMAE0ATQBPAE4A"),
|
||||||
|
"material": SubResource("StandardMaterial3D_urtjv"),
|
||||||
|
"name": "pink",
|
||||||
|
"primitive": 3,
|
||||||
|
"uv_scale": Vector4(0.787402, 4.3622, 0, 0),
|
||||||
|
"vertex_count": 80,
|
||||||
|
"vertex_data": PackedByteArray("/98AAP/f/MX/31TV/9/8xf//AAD/f1TV//9U1f9/VNX/3wAA/9/8xf9/AAD//////99U1f/f/MX/f1TV//////9/AAD//////x8AAP/f/MX/f1TV//////8fVNX/3/zF/x9U1f/f/MX/HwAA/9/8xQAAVNX/f1TVAAAAAP9/VNX/fwAAAAD////fAAD/H6rp/39U1QAA////31TV/x+q6QAAAAD/f1TV/x8AAP/fVNX/HwAA/x9U1f9/AAAAAFTV/38AAP//VNX/3wAA/x9U1f/fAAD/31TV//8AAP9/VNUAAFTV/39U1QAAAAD/f1TV/x9U1f8fqun/HwAA/x+q6f8fAAD/H6rp/38AAAAA////H1TV/x+q6f9/VNUAAP////8AAP9/VNX//1TV/39U1f/fAAD/H6rp/99U1f8fqun/H////3//v/83////N/+//zf////H/7//f////9//v/9/////H/+//8f////H/7//x////zf/v//f////f/+//39U1QAAmP//31TV/x8E4f9/////H5j//8f///83BOH/H1TV/x8E4f9/VNUAAJj//zf///83BOH/f////x+Y//9/VNX//4CK/x9U1f/fWKH/f////9+Aiv83////x1ih/x////9/EcEAAFTV/38Rwf83////N63f/x9U1f8frd//H1TV/9+cogAAVNX/f0XA/zf////HnKL/H////39FwP/fVNX/31ih/39U1f//gIr/x////8dYof9/////34CK/99U1f/fnKL/x////8ecov//VNX/f0XA/9////9/RcD//1TV/38Rwf/f////fxHB/99U1f8frd//x////zet3/9/AAD/fwAA/38AAP9/AAD/fwAA/3//f/9/AAD/f/9//3//f/9/////f/9//3////9/////f////3////9/////f////38AAP9/////fwAAAAD/fwAA/38AAP9/AAD/fwAA/38AAP9/AAD/fwAA/3//f////3////9/////f////3////9/////f////3////9/AAD/fwAA/38AAP9/AAD+//9/////f/7//3////9/////f////3/+//9//v//f/uRcATFbRMB+5FwBMVtEwHsfsXtcIQD7ux+xe1whAPujd3Ggz6l8tyN3caDPqXy3HaIzuZ2iM7mYIyz6GCMs+iklPLT2pCb5qSU8tPakJvmDKM/JTj8jV0Moz8lOPyNXQuspBQLrKQUY5nbEGOZ2xAvmXcIL5l3CEqXYAxKl2AM")
|
||||||
|
}]
|
||||||
|
blend_shape_mode = 0
|
||||||
|
shadow_mesh = SubResource("ArrayMesh_iqbgl")
|
||||||
|
|
||||||
|
[sub_resource type="CylinderShape3D" id="CylinderShape3D_r5ds2"]
|
||||||
|
height = 0.202453
|
||||||
|
radius = 0.0673677
|
||||||
|
|
||||||
|
[node name="RigidBody3D" type="RigidBody3D"]
|
||||||
|
gravity_scale = 0.0
|
||||||
|
continuous_cd = true
|
||||||
|
contact_monitor = true
|
||||||
|
max_contacts_reported = 5
|
||||||
|
|
||||||
|
[node name="foamBulletB-low" type="MeshInstance3D" parent="."]
|
||||||
|
transform = Transform3D(10, 0, 0, 0, -4.37114e-07, 10, 0, -10, -4.37114e-07, 0, 0, 0)
|
||||||
|
mesh = SubResource("ArrayMesh_mt61o")
|
||||||
|
skeleton = NodePath("")
|
||||||
|
|
||||||
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 0, 0)
|
||||||
|
shape = SubResource("CylinderShape3D_r5ds2")
|
||||||
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
BIN
Binary file not shown.
File diff suppressed because one or more lines are too long
@@ -0,0 +1,36 @@
|
|||||||
|
extends CanvasLayer
|
||||||
|
|
||||||
|
@onready var current_weapon_label = $debug_hud/HBoxContainer/CurrentWeapon
|
||||||
|
@onready var current_ammo_label = $debug_hud/HBoxContainer2/CurrentAmmo
|
||||||
|
@onready var current_weapon_stack = $debug_hud/HBoxContainer3/WeaponStack
|
||||||
|
@onready var hit_sight = $HitSight
|
||||||
|
@onready var hit_sight_timer = $HitSight/HitSightTimer
|
||||||
|
@onready var overLay = $Overlay
|
||||||
|
|
||||||
|
func _on_weapons_manager_update_weapon_stack(WeaponStack):
|
||||||
|
current_weapon_stack.text = ""
|
||||||
|
for i in WeaponStack:
|
||||||
|
current_weapon_stack.text += "\n"+i.weapon.weapon_name
|
||||||
|
|
||||||
|
func _on_weapons_manager_update_ammo(Ammo):
|
||||||
|
current_ammo_label.set_text(str(Ammo[0])+" / "+str(Ammo[1]))
|
||||||
|
|
||||||
|
func _on_weapons_manager_weapon_changed(WeaponName):
|
||||||
|
current_weapon_label.set_text(WeaponName)
|
||||||
|
|
||||||
|
func _on_hit_sight_timer_timeout():
|
||||||
|
hit_sight.set_visible(false)
|
||||||
|
|
||||||
|
func _on_weapons_manager_add_signal_to_hud(_projectile):
|
||||||
|
_projectile.Hit_Successfull.connect(_on_weapons_manager_hit_successfull)
|
||||||
|
|
||||||
|
func _on_weapons_manager_hit_successfull():
|
||||||
|
hit_sight.set_visible(true)
|
||||||
|
hit_sight_timer.start()
|
||||||
|
|
||||||
|
func load_over_lay_texture(Active:bool, txtr: Texture2D = null):
|
||||||
|
overLay.set_texture(txtr)
|
||||||
|
overLay.set_visible(Active)
|
||||||
|
|
||||||
|
func _on_weapons_manager_connect_weapon_to_hud(_weapon_resouce: WeaponResource):
|
||||||
|
_weapon_resouce.update_overlay.connect(load_over_lay_texture)
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://cc3t6vk7qpwey
|
||||||
@@ -0,0 +1,266 @@
|
|||||||
|
extends CharacterBody3D
|
||||||
|
|
||||||
|
@onready var camera = %Camera
|
||||||
|
@export var subviewport_camera: Camera3D
|
||||||
|
@export var main_camera:Camera3D
|
||||||
|
@export var animation_tree: AnimationTree
|
||||||
|
|
||||||
|
var camera_rotation: Vector2 = Vector2(0.0,0.0)
|
||||||
|
var mouse_sensitivity = 0.001
|
||||||
|
var crouched: bool = false
|
||||||
|
var crouch_blocked: bool = false
|
||||||
|
|
||||||
|
@export_category("Crouch Parametres")
|
||||||
|
@export var enable_crouch: bool = true
|
||||||
|
@export var crouch_toggle: bool = false
|
||||||
|
@export var crouch_collision: ShapeCast3D
|
||||||
|
@export_range(0.0,3.0) var crouch_speed_reduction = 2.0
|
||||||
|
@export_range(0.0,0.50) var crouch_blend_speed = .2
|
||||||
|
enum {GROUND_CROUCH = -1, STANDING = 0, AIR_CROUCH = 1}
|
||||||
|
|
||||||
|
@export_category("Lean Parametres")
|
||||||
|
@export var enable_lean: bool = true
|
||||||
|
@export_range(0.0,1.0) var lean_speed: float = .2
|
||||||
|
@export var right_lean_collision: ShapeCast3D
|
||||||
|
@export var left_lean_collision: ShapeCast3D
|
||||||
|
var lean_tween
|
||||||
|
enum {LEFT = 1, CENTRE = 0, RIGHT = -1}
|
||||||
|
|
||||||
|
@export_category("speed Parameters")
|
||||||
|
@export var enable_sprint: bool = true
|
||||||
|
@export var sprint_timer: Timer
|
||||||
|
@export var sprint_cooldown_time: float = 3.0
|
||||||
|
@export var sprint_time: float = 1.0
|
||||||
|
@export var sprint_replenish_rate: float = 0.30
|
||||||
|
@export var acceleration: float = 120
|
||||||
|
@export_range(0.01,1.0) var air_acceleration_modifier: float = 0.1
|
||||||
|
var sprint_on_cooldown: bool = false
|
||||||
|
var sprint_time_remaining: float = sprint_time
|
||||||
|
@onready var sprint_bar: Range = $CanvasLayer/SprintBar
|
||||||
|
|
||||||
|
const NORMAL_speed = 1
|
||||||
|
@export_range(1.0,3.0) var sprint_speed: float = 2.0
|
||||||
|
@export_range(0.1,1.0) var walk_speed: float = 0.5
|
||||||
|
var speed_modifier: float = NORMAL_speed
|
||||||
|
|
||||||
|
@export_category("Jump Parameters")
|
||||||
|
@export var coyote_timer: Timer
|
||||||
|
@export var jump_peak_time: float = .5
|
||||||
|
@export var jump_fall_time: float = .5
|
||||||
|
@export var jump_height: float = 2.0
|
||||||
|
@export var jump_distance: float = 4.0
|
||||||
|
@export var coyote_time: float = .1
|
||||||
|
@export var jump_buffer_time: float = .2
|
||||||
|
|
||||||
|
# Get the gravity from the project settings to be synced with RigidBody nodes.
|
||||||
|
var jump_gravity = ProjectSettings.get_setting("physics/3d/default_gravity")
|
||||||
|
var fall_gravity: float
|
||||||
|
var jump_velocity: float
|
||||||
|
var base_speed: float
|
||||||
|
var _speed: float
|
||||||
|
var jump_available: bool = true
|
||||||
|
var jump_buffer: bool = false
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
update_camera_rotation()
|
||||||
|
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
|
||||||
|
calculate_movement_parameters()
|
||||||
|
|
||||||
|
func update_camera_rotation() -> void:
|
||||||
|
var current_rotation = get_rotation()
|
||||||
|
camera_rotation.x = current_rotation.y
|
||||||
|
camera_rotation.y = current_rotation.x
|
||||||
|
|
||||||
|
|
||||||
|
func _input(event: InputEvent) -> void:
|
||||||
|
if event.is_action_pressed("ui_cancel"):
|
||||||
|
if Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED:
|
||||||
|
Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
|
||||||
|
else:
|
||||||
|
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
|
||||||
|
|
||||||
|
if event is InputEventMouseMotion:
|
||||||
|
var MouseEvent = event.relative * mouse_sensitivity
|
||||||
|
camera_look(MouseEvent)
|
||||||
|
|
||||||
|
if enable_crouch:
|
||||||
|
if event.is_action_pressed("crouch"):
|
||||||
|
crouch()
|
||||||
|
if event.is_action_released("crouch"):
|
||||||
|
if !crouch_toggle and crouched:
|
||||||
|
crouch()
|
||||||
|
|
||||||
|
if enable_lean:
|
||||||
|
if Input.is_action_just_released("lean_left") or Input.is_action_just_released("lean_right"):
|
||||||
|
if !(Input.is_action_pressed("lean_right") or Input.is_action_pressed("lean_left")):
|
||||||
|
lean(CENTRE)
|
||||||
|
if Input.is_action_just_pressed("lean_left"):
|
||||||
|
lean(LEFT)
|
||||||
|
if Input.is_action_just_pressed("lean_right"):
|
||||||
|
lean(RIGHT)
|
||||||
|
|
||||||
|
if enable_sprint:
|
||||||
|
if Input.is_action_just_pressed("sprint") and !crouched:
|
||||||
|
if !sprint_on_cooldown:
|
||||||
|
speed_modifier = sprint_speed
|
||||||
|
sprint_timer.start(sprint_time_remaining)
|
||||||
|
|
||||||
|
if Input.is_action_just_released("sprint") or Input.is_action_just_released("walk"):
|
||||||
|
if !(Input.is_action_pressed("walk") or Input.is_action_pressed("sprint")):
|
||||||
|
speed_modifier = NORMAL_speed
|
||||||
|
exit_sprint()
|
||||||
|
|
||||||
|
if Input.is_action_just_pressed("walk") and !crouched:
|
||||||
|
speed_modifier = walk_speed
|
||||||
|
|
||||||
|
func calculate_movement_parameters() -> void:
|
||||||
|
jump_gravity = (2*jump_height)/pow(jump_peak_time,2)
|
||||||
|
fall_gravity = (2*jump_height)/pow(jump_fall_time,2)
|
||||||
|
jump_velocity = jump_gravity * jump_peak_time
|
||||||
|
base_speed = jump_distance/(jump_peak_time+jump_fall_time)
|
||||||
|
_speed = base_speed
|
||||||
|
|
||||||
|
func lean(blend_amount: int) -> void:
|
||||||
|
if is_on_floor():
|
||||||
|
if lean_tween:
|
||||||
|
lean_tween.kill()
|
||||||
|
|
||||||
|
lean_tween = get_tree().create_tween()
|
||||||
|
lean_tween.tween_property(animation_tree,"parameters/lean_blend/blend_amount", blend_amount, lean_speed)
|
||||||
|
|
||||||
|
func lean_collision() -> void:
|
||||||
|
animation_tree["parameters/left_collision_blend/blend_amount"] = lerp(
|
||||||
|
float(animation_tree["parameters/left_collision_blend/blend_amount"]),float(left_lean_collision.is_colliding()),lean_speed
|
||||||
|
)
|
||||||
|
animation_tree["parameters/right_collision_blend/blend_amount"] = lerp(
|
||||||
|
float(animation_tree["parameters/right_collision_blend/blend_amount"]),float(right_lean_collision.is_colliding()),lean_speed
|
||||||
|
)
|
||||||
|
|
||||||
|
func crouch() -> void:
|
||||||
|
var Blend
|
||||||
|
if !crouch_collision.is_colliding():
|
||||||
|
if crouched:
|
||||||
|
Blend = STANDING
|
||||||
|
else:
|
||||||
|
speed_modifier = NORMAL_speed
|
||||||
|
exit_sprint()
|
||||||
|
|
||||||
|
if is_on_floor():
|
||||||
|
Blend = GROUND_CROUCH
|
||||||
|
else:
|
||||||
|
Blend = AIR_CROUCH
|
||||||
|
var blend_tween = get_tree().create_tween()
|
||||||
|
blend_tween.tween_property(animation_tree,"parameters/Crouch_Blend/blend_amount",Blend,crouch_blend_speed)
|
||||||
|
crouched = !crouched
|
||||||
|
else:
|
||||||
|
crouch_blocked = true
|
||||||
|
|
||||||
|
func camera_look(Movement: Vector2) -> void:
|
||||||
|
camera_rotation += Movement
|
||||||
|
|
||||||
|
transform.basis = Basis()
|
||||||
|
camera.transform.basis = Basis()
|
||||||
|
|
||||||
|
rotate_object_local(Vector3(0,1,0),-camera_rotation.x) # first rotate in Y
|
||||||
|
camera.rotate_object_local(Vector3(1,0,0), -camera_rotation.y) # then rotate in X
|
||||||
|
camera_rotation.y = clamp(camera_rotation.y,-1.5,1.2)
|
||||||
|
|
||||||
|
func exit_sprint() -> void:
|
||||||
|
if !sprint_timer.is_stopped():
|
||||||
|
sprint_time_remaining = sprint_timer.time_left
|
||||||
|
sprint_timer.stop()
|
||||||
|
|
||||||
|
func sprint_replenish(delta) -> void:
|
||||||
|
var sprint_bar_Value
|
||||||
|
|
||||||
|
if !sprint_on_cooldown and (speed_modifier != sprint_speed):
|
||||||
|
|
||||||
|
if is_on_floor():
|
||||||
|
sprint_time_remaining = move_toward(sprint_time_remaining, sprint_time, delta*sprint_replenish_rate)
|
||||||
|
|
||||||
|
sprint_bar_Value= (sprint_time_remaining/sprint_time)*100
|
||||||
|
|
||||||
|
else:
|
||||||
|
sprint_bar_Value = (sprint_timer.time_left/sprint_time)*100
|
||||||
|
|
||||||
|
sprint_bar.value = sprint_bar_Value
|
||||||
|
|
||||||
|
if sprint_bar_Value == 100:
|
||||||
|
sprint_bar.hide()
|
||||||
|
else:
|
||||||
|
sprint_bar.show()
|
||||||
|
|
||||||
|
func _process(_delta: float) -> void:
|
||||||
|
if subviewport_camera:
|
||||||
|
subviewport_camera.global_transform = main_camera.global_transform
|
||||||
|
|
||||||
|
|
||||||
|
func _physics_process(_delta: float) -> void:
|
||||||
|
sprint_replenish(_delta)
|
||||||
|
lean_collision()
|
||||||
|
|
||||||
|
if crouched and crouch_blocked:
|
||||||
|
if !crouch_collision.is_colliding():
|
||||||
|
crouch_blocked = false
|
||||||
|
if !Input.is_action_pressed("crouch") and !crouch_toggle:
|
||||||
|
crouch()
|
||||||
|
|
||||||
|
# Add the gravity.
|
||||||
|
var _acceleration
|
||||||
|
if not is_on_floor():
|
||||||
|
_acceleration = acceleration*air_acceleration_modifier
|
||||||
|
|
||||||
|
if coyote_timer.is_stopped():
|
||||||
|
coyote_timer.start(coyote_time)
|
||||||
|
|
||||||
|
if velocity.y>0:
|
||||||
|
velocity.y -= jump_gravity * _delta
|
||||||
|
else:
|
||||||
|
velocity.y -= fall_gravity * _delta
|
||||||
|
else:
|
||||||
|
_acceleration = acceleration
|
||||||
|
jump_available = true
|
||||||
|
coyote_timer.stop()
|
||||||
|
_speed = (base_speed / max((float(crouched)*crouch_speed_reduction),1)) * speed_modifier
|
||||||
|
if jump_buffer:
|
||||||
|
jump()
|
||||||
|
jump_buffer = false
|
||||||
|
# Handle Jump.
|
||||||
|
if Input.is_action_just_pressed("ui_accept"):
|
||||||
|
if jump_available:
|
||||||
|
if crouched:
|
||||||
|
crouch()
|
||||||
|
else:
|
||||||
|
lean(CENTRE)
|
||||||
|
jump()
|
||||||
|
else:
|
||||||
|
jump_buffer = true
|
||||||
|
get_tree().create_timer(jump_buffer_time).timeout.connect(on_jump_buffer_timeout)
|
||||||
|
|
||||||
|
# Get the input direction and handle the movement/deceleration.
|
||||||
|
# As good practice, you should replace UI actions with custom gameplay actions.
|
||||||
|
var input_dir = Input.get_vector("left", "right", "up", "down")
|
||||||
|
var direction = (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
|
||||||
|
velocity.x = move_toward(velocity.x, direction.x * _speed, _acceleration*_delta)
|
||||||
|
velocity.z = move_toward(velocity.z, direction.z * _speed, _acceleration*_delta)
|
||||||
|
|
||||||
|
move_and_slide()
|
||||||
|
|
||||||
|
func jump()->void:
|
||||||
|
velocity.y = jump_velocity
|
||||||
|
jump_available = false
|
||||||
|
|
||||||
|
func _on_sprint_timer_timeout() -> void:
|
||||||
|
sprint_on_cooldown = true
|
||||||
|
get_tree().create_timer(sprint_cooldown_time).timeout.connect(_on_sprint_cooldown_timeout)
|
||||||
|
speed_modifier = NORMAL_speed
|
||||||
|
sprint_time_remaining = 0
|
||||||
|
|
||||||
|
func _on_sprint_cooldown_timeout():
|
||||||
|
sprint_on_cooldown = false
|
||||||
|
|
||||||
|
func _on_coyote_timer_timeout() -> void:
|
||||||
|
jump_available = false
|
||||||
|
|
||||||
|
func on_jump_buffer_timeout()->void:
|
||||||
|
jump_buffer = false
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://cfdt8t4r8pxel
|
||||||
@@ -0,0 +1,137 @@
|
|||||||
|
extends Node3D
|
||||||
|
class_name Projectile
|
||||||
|
|
||||||
|
signal Hit_Successfull
|
||||||
|
|
||||||
|
## Can Be Either A Hit Scan or Rigid Body Projectile. If Rigid body is select a Rigid body must be provided.
|
||||||
|
@export_enum ("Hitscan","Rigidbody_Projectile","over_ride") var Projectile_Type: String = "Hitscan"
|
||||||
|
@export var Display_Debug_Decal: bool = true
|
||||||
|
|
||||||
|
@export_category("Rigid Body Projectile Properties")
|
||||||
|
@export var Projectile_Velocity: int
|
||||||
|
@export var Expirey_Time: int = 10
|
||||||
|
@export var Rigid_Body_Projectile: PackedScene
|
||||||
|
@export var pass_through: bool = false
|
||||||
|
|
||||||
|
@onready var Debug_Bullet = preload("res://client/template/Spawnable_Objects/hit_debug.tscn")
|
||||||
|
|
||||||
|
var damage: float = 0
|
||||||
|
var Projectiles_Spawned = []
|
||||||
|
var hit_objects: Array = []
|
||||||
|
|
||||||
|
# Called when the node enters the scene tree for the first time.
|
||||||
|
func _ready() -> void:
|
||||||
|
get_tree().create_timer(Expirey_Time).timeout.connect(_on_timer_timeout)
|
||||||
|
|
||||||
|
func _Set_Projectile(_damage: int = 0,_spread:Vector2 = Vector2.ZERO, _Range: int = 1000, origin_point: Vector3 = Vector3.ZERO):
|
||||||
|
damage = _damage
|
||||||
|
Fire_Projectile(_spread,_Range,Rigid_Body_Projectile, origin_point)
|
||||||
|
|
||||||
|
func Fire_Projectile(_spread: Vector2 ,_range: int, _proj:PackedScene, origin_point: Vector3):
|
||||||
|
var Camera_Collision = Camera_Ray_Cast(_spread,_range)
|
||||||
|
|
||||||
|
match Projectile_Type:
|
||||||
|
"Hitscan":
|
||||||
|
Hit_Scan_Collision(Camera_Collision, damage,origin_point)
|
||||||
|
"Rigidbody_Projectile":
|
||||||
|
Launch_Rigid_Body_Projectile(Camera_Collision, _proj,origin_point)
|
||||||
|
"over_ride":
|
||||||
|
_over_ride_collision(Camera_Collision, damage)
|
||||||
|
|
||||||
|
func _over_ride_collision(_camera_collision:Array, _damage: float) -> void:
|
||||||
|
pass
|
||||||
|
|
||||||
|
func Camera_Ray_Cast(_spread: Vector2 = Vector2.ZERO, _range: float = 1000):
|
||||||
|
var _Camera = get_viewport().get_camera_3d()
|
||||||
|
var _Viewport = get_viewport().get_size()
|
||||||
|
|
||||||
|
var Ray_Origin = _Camera.project_ray_origin(_Viewport/2)
|
||||||
|
var Ray_End = (Ray_Origin + _Camera.project_ray_normal((_Viewport/2)+Vector2i(_spread)) *_range)
|
||||||
|
var New_Intersection:PhysicsRayQueryParameters3D = PhysicsRayQueryParameters3D.create(Ray_Origin,Ray_End)
|
||||||
|
New_Intersection.set_collision_mask(0b11101101)
|
||||||
|
New_Intersection.set_hit_from_inside(false) # In Jolt this is set to true by defualt
|
||||||
|
|
||||||
|
var Intersection = get_world_3d().direct_space_state.intersect_ray(New_Intersection)
|
||||||
|
|
||||||
|
if not Intersection.is_empty():
|
||||||
|
var Collision = [Intersection.collider,Intersection.position,Intersection.normal]
|
||||||
|
return Collision
|
||||||
|
else:
|
||||||
|
return [null,Ray_End,null]
|
||||||
|
|
||||||
|
func Hit_Scan_Collision(Collision: Array,_damage: float, origin_point: Vector3):
|
||||||
|
var Point = Collision[1]
|
||||||
|
if Collision[0]:
|
||||||
|
Load_Decal(Point, Collision[2])
|
||||||
|
|
||||||
|
if Collision[0].is_in_group("Target"):
|
||||||
|
var Bullet = get_world_3d().direct_space_state
|
||||||
|
|
||||||
|
var Bullet_Direction = (Point - origin_point).normalized()
|
||||||
|
var New_Intersection = PhysicsRayQueryParameters3D.create(origin_point,Point+Bullet_Direction*2)
|
||||||
|
New_Intersection.set_collision_mask(0b11101101)
|
||||||
|
New_Intersection.set_hit_from_inside(false)
|
||||||
|
New_Intersection.set_exclude(hit_objects)
|
||||||
|
var Bullet_Collision = Bullet.intersect_ray(New_Intersection)
|
||||||
|
|
||||||
|
if Bullet_Collision:
|
||||||
|
Hit_Scan_damage(Bullet_Collision.collider, Bullet_Direction,Bullet_Collision.position,_damage)
|
||||||
|
if pass_through and check_pass_through(Bullet_Collision.collider, Bullet_Collision.rid):
|
||||||
|
var pass_through_collision : Array = [Bullet_Collision.collider, Bullet_Collision.position, Bullet_Collision.normal]
|
||||||
|
var pass_through_damage: float = damage/2
|
||||||
|
Hit_Scan_Collision(pass_through_collision,pass_through_damage,Bullet_Collision.position)
|
||||||
|
return
|
||||||
|
queue_free()
|
||||||
|
|
||||||
|
func check_pass_through(collider: Node3D, rid: RID)-> bool:
|
||||||
|
var valid_pass_though: bool = false
|
||||||
|
if collider.is_in_group("Pass Through"):
|
||||||
|
hit_objects.append(rid)
|
||||||
|
valid_pass_though = true
|
||||||
|
return valid_pass_though
|
||||||
|
|
||||||
|
func Hit_Scan_damage(Collider, Direction, Position, _damage):
|
||||||
|
if Collider.is_in_group("Target") and Collider.has_method("Hit_Successful"):
|
||||||
|
Hit_Successfull.emit()
|
||||||
|
Collider.Hit_Successful(_damage, Direction, Position)
|
||||||
|
|
||||||
|
|
||||||
|
func Load_Decal(_pos,_normal):
|
||||||
|
if Display_Debug_Decal:
|
||||||
|
var rd = Debug_Bullet.instantiate()
|
||||||
|
var world = get_tree().get_root()
|
||||||
|
world.add_child(rd)
|
||||||
|
rd.global_translate(_pos+(_normal*.01))
|
||||||
|
|
||||||
|
func Launch_Rigid_Body_Projectile(Collision_Data, _projectile, _origin_point):
|
||||||
|
var _Point = Collision_Data[1]
|
||||||
|
var _Norm = Collision_Data[2]
|
||||||
|
var _proj : RigidBody3D = _projectile.instantiate()
|
||||||
|
_proj.position = _origin_point
|
||||||
|
|
||||||
|
var world = get_tree().get_first_node_in_group("World")
|
||||||
|
world.add_child(_proj)
|
||||||
|
|
||||||
|
_proj.look_at(_Point)
|
||||||
|
Projectiles_Spawned.push_back(_proj)
|
||||||
|
|
||||||
|
_proj.body_entered.connect(_on_body_entered.bind(_proj,_Norm))
|
||||||
|
|
||||||
|
var _Direction = (_Point - _origin_point).normalized()
|
||||||
|
_proj.set_linear_velocity(_Direction*Projectile_Velocity)
|
||||||
|
|
||||||
|
func _on_body_entered(body, _proj, _norm):
|
||||||
|
if body.is_in_group("Target") && body.has_method("Hit_Successful"):
|
||||||
|
body.Hit_Successful(damage)
|
||||||
|
Hit_Successfull.emit()
|
||||||
|
|
||||||
|
Load_Decal(_proj.get_position(),_norm)
|
||||||
|
_proj.queue_free()
|
||||||
|
|
||||||
|
Projectiles_Spawned.erase(_proj)
|
||||||
|
|
||||||
|
if Projectiles_Spawned.is_empty():
|
||||||
|
queue_free()
|
||||||
|
|
||||||
|
func _on_timer_timeout():
|
||||||
|
queue_free()
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://b26eegme16mfw
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
extends Projectile
|
||||||
|
|
||||||
|
@onready var melee_hitbox: ShapeCast3D = $MeleeHitbox
|
||||||
|
|
||||||
|
func _over_ride_collision(_camera_collision:Array, _damage: float):
|
||||||
|
melee_hitbox.force_shapecast_update()
|
||||||
|
var colliders = melee_hitbox.get_collision_count()
|
||||||
|
for c in colliders:
|
||||||
|
var Target = melee_hitbox.get_collider(c)
|
||||||
|
if Target.is_in_group("Target") and Target.has_method("Hit_Successful"):
|
||||||
|
Hit_Successfull.emit()
|
||||||
|
var Direction = (Target.global_transform.origin - global_transform.origin).normalized()
|
||||||
|
var Position = melee_hitbox.get_collision_point(c)
|
||||||
|
Target.Hit_Successful(_damage, Direction, Position)
|
||||||
|
queue_free()
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://bfn8eu00l4btq
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
extends Projectile
|
||||||
|
|
||||||
|
@export var explosion: ShapeCast3D
|
||||||
|
|
||||||
|
func _on_body_entered(_body, _proj, _norm):
|
||||||
|
var collision_location: Vector3 = _proj.global_position
|
||||||
|
explosion.global_position = collision_location
|
||||||
|
|
||||||
|
explosion.force_shapecast_update()
|
||||||
|
var targets = explosion.get_collision_count()
|
||||||
|
|
||||||
|
for t in targets:
|
||||||
|
var damage_target = explosion.get_collider(t)
|
||||||
|
var collision_point: Vector3 = explosion.get_collision_point(t)
|
||||||
|
var collision_normal: Vector3 = explosion.get_collision_normal(t)
|
||||||
|
var hit_scan_array = [damage_target,collision_point,collision_normal]
|
||||||
|
Hit_Scan_Collision(hit_scan_array,damage,collision_location)
|
||||||
|
|
||||||
|
_proj.queue_free()
|
||||||
|
Projectiles_Spawned.erase(_proj)
|
||||||
|
|
||||||
|
if Projectiles_Spawned.is_empty():
|
||||||
|
queue_free()
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://biivm72fp7af8
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
extends Projectile
|
||||||
|
|
||||||
|
@onready var shotgun_pattern: Path2D = $shotgun_pattern
|
||||||
|
@export_range(0.0,20.0) var Randomness = 10.0
|
||||||
|
@export var Split_damage: bool = false
|
||||||
|
var Spray_Vector
|
||||||
|
|
||||||
|
# Called when the node enters the scene tree for the first time.
|
||||||
|
func _ready() -> void:
|
||||||
|
Spray_Vector = shotgun_pattern.get_curve()
|
||||||
|
return super._ready()
|
||||||
|
|
||||||
|
func _Set_Projectile(_damage: int = 0,_spread:Vector2 = Vector2.ZERO, _Range: int = 1000, origin_point: Vector3 = Vector3.ZERO):
|
||||||
|
randomize()
|
||||||
|
damage = _damage/(max(Spray_Vector.get_point_count()*float(Split_damage),1))
|
||||||
|
|
||||||
|
for point in Spray_Vector.get_point_count():
|
||||||
|
var SprayPoint:Vector2 = Spray_Vector.get_point_position(point)
|
||||||
|
|
||||||
|
SprayPoint.x = SprayPoint.x + randf_range(-Randomness, Randomness)
|
||||||
|
SprayPoint.y = SprayPoint.y + randf_range(-Randomness, Randomness)
|
||||||
|
|
||||||
|
Fire_Projectile(SprayPoint,_Range,Rigid_Body_Projectile, origin_point)
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://dnh4a4vkl0cl1
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
extends RigidBody3D
|
||||||
|
class_name WeaponPickUp
|
||||||
|
|
||||||
|
@export var weapon: WeaponSlot
|
||||||
|
@export_enum("Weapon","Ammo") var TYPE = "Weapon"
|
||||||
|
|
||||||
|
var Pick_Up_Ready: bool = false
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
await get_tree().create_timer(2.0).timeout
|
||||||
|
Pick_Up_Ready = true
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://deaf6cmuofa0
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
extends RigidBody3D
|
||||||
|
|
||||||
|
@export var _weapon_name: String
|
||||||
|
@export var _current_ammo: int
|
||||||
|
@export var _reserve_ammo: int
|
||||||
|
|
||||||
|
const TYPE = "Ammo"
|
||||||
|
|
||||||
|
var Pick_Up_Ready: bool = false
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
await get_tree().create_timer(2.0).timeout
|
||||||
|
Pick_Up_Ready = true
|
||||||
|
|
||||||
|
func Set_Ammo(w_name: String, c_ammo : int, r_ammo : int):
|
||||||
|
if w_name == _weapon_name:
|
||||||
|
_current_ammo = c_ammo
|
||||||
|
_reserve_ammo = r_ammo
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://dvxmf6dpx0qdn
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
extends Resource
|
||||||
|
class_name WeaponSlot
|
||||||
|
|
||||||
|
@export var weapon: WeaponResource
|
||||||
|
|
||||||
|
@export var current_ammo: int
|
||||||
|
@export var reserve_ammo: int
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://bw4j1fbww4k8s
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
[gd_resource type="Resource" script_class="WeaponResource" load_steps=3 format=3 uid="uid://ckwagka0u7opy"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://ca7h24lxxrtvx" path="res://client/template/scripts/Weapon_State_Machine/weapon_resource.gd" id="1_2o2yi"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://6rfh1ejt4m6m" path="res://client/template/Spawnable_Objects/Projectiles_To_Load/melee_projectile.tscn" id="1_pf8fu"]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
script = ExtResource("1_2o2yi")
|
||||||
|
weapon_name = "MeleeWeapon"
|
||||||
|
pick_up_animation = "blasterP_activate"
|
||||||
|
shoot_animation = "blasterP_strike"
|
||||||
|
reload_animation = ""
|
||||||
|
change_animation = "blasterP_deactivate"
|
||||||
|
drop_animation = ""
|
||||||
|
out_of_ammo_animation = ""
|
||||||
|
melee_animation = "blasterP_strike"
|
||||||
|
has_ammo = false
|
||||||
|
magazine = 0
|
||||||
|
max_ammo = 0
|
||||||
|
damage = 2
|
||||||
|
melee_damage = 1.0
|
||||||
|
auto_fire = true
|
||||||
|
fire_range = 1
|
||||||
|
can_be_dropped = false
|
||||||
|
projectile_to_load = ExtResource("1_pf8fu")
|
||||||
|
incremental_reload = false
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
[gd_resource type="Resource" script_class="WeaponResource" format=3 uid="uid://yc1f2j7pl4vr"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://ca7h24lxxrtvx" path="res://client/template/scripts/Weapon_State_Machine/weapon_resource.gd" id="1_jgxyc"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://dc48o4niy1mok" path="res://client/template/Spawnable_Objects/Projectiles_To_Load/basic_hitscan_projectile.tscn" id="1_l4j8x"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://cvbk5bxenpxey" path="res://client/template/Spawnable_Objects/Weapons/blaster_I.tscn" id="3_y2nwe"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://ciu0xkaw0ioef" path="res://client/template/Spawnable_Objects/SprayProfiles/spray_profile_1.tscn" id="4_xc0or"]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
script = ExtResource("1_jgxyc")
|
||||||
|
weapon_name = "blasterI"
|
||||||
|
pick_up_animation = "Global/blasterI Active"
|
||||||
|
shoot_animation = "Global/blasterI Shoot"
|
||||||
|
reload_animation = "Global/blasterI Reload"
|
||||||
|
change_animation = "Global/blasterI De-Activate"
|
||||||
|
drop_animation = "Global/blasterI Drop"
|
||||||
|
out_of_ammo_animation = "Global/blasterI OOA"
|
||||||
|
melee_animation = "Global/blasterI Melee"
|
||||||
|
magazine = 30
|
||||||
|
max_ammo = 60
|
||||||
|
damage = 10
|
||||||
|
melee_damage = 1.0
|
||||||
|
auto_fire = true
|
||||||
|
fire_range = 100
|
||||||
|
can_be_dropped = true
|
||||||
|
weapon_drop = ExtResource("3_y2nwe")
|
||||||
|
weapon_spray = ExtResource("4_xc0or")
|
||||||
|
projectile_to_load = ExtResource("1_l4j8x")
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
[gd_resource type="Resource" script_class="WeaponResource" load_steps=5 format=3 uid="uid://bwrs8ensewkgc"]
|
||||||
|
|
||||||
|
[ext_resource type="PackedScene" uid="uid://bpxa3je174q43" path="res://client/template/Spawnable_Objects/Projectiles_To_Load/basic_rigid_body_projectile.tscn" id="1_1tllq"]
|
||||||
|
[ext_resource type="Script" uid="uid://ca7h24lxxrtvx" path="res://client/template/scripts/Weapon_State_Machine/weapon_resource.gd" id="2_gpxoe"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://gtthejj2wmyj" path="res://client/template/Spawnable_Objects/Weapons/blaster_n.tscn" id="3_5a5l8"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://3mb12hvruajh" path="res://client/template/Spawnable_Objects/SprayProfiles/spray_profile_2.tscn" id="4_p50xh"]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
script = ExtResource("2_gpxoe")
|
||||||
|
weapon_name = "blasterN"
|
||||||
|
pick_up_animation = "Global/blasterL Activate"
|
||||||
|
shoot_animation = "Global/blasterL Shoot"
|
||||||
|
reload_animation = "Global/blasterL Reload"
|
||||||
|
change_animation = "Global/blasterL De-Activate"
|
||||||
|
drop_animation = "Global/blasterL Drop"
|
||||||
|
out_of_ammo_animation = "Global/blasterL OOA"
|
||||||
|
melee_animation = "Global/blasterL Melee"
|
||||||
|
has_ammo = true
|
||||||
|
magazine = 30
|
||||||
|
max_ammo = 60
|
||||||
|
damage = 1
|
||||||
|
melee_damage = 1.0
|
||||||
|
auto_fire = true
|
||||||
|
fire_range = 100
|
||||||
|
can_be_dropped = true
|
||||||
|
weapon_drop = ExtResource("3_5a5l8")
|
||||||
|
weapon_spray = ExtResource("4_p50xh")
|
||||||
|
projectile_to_load = ExtResource("1_1tllq")
|
||||||
|
incremental_reload = false
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
[gd_resource type="Resource" script_class="WeaponResource" load_steps=5 format=3 uid="uid://cd8msvjysh2uv"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://ca7h24lxxrtvx" path="res://client/template/scripts/Weapon_State_Machine/weapon_resource.gd" id="1_4ro7h"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://brvfyahytwd8m" path="res://client/template/Spawnable_Objects/Projectiles_To_Load/shotgun_projectile.tscn" id="1_qi0jo"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://x8nhs2cer2to" path="res://client/template/Spawnable_Objects/Weapons/blaster_m.tscn" id="3_5hojr"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://ceuaamuau8pl8" path="res://client/template/Spawnable_Objects/SprayProfiles/spray_profile_3.tscn" id="4_5jfrh"]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
script = ExtResource("1_4ro7h")
|
||||||
|
weapon_name = "blasterM"
|
||||||
|
pick_up_animation = "blasterM_activate"
|
||||||
|
shoot_animation = "blasterM_Shoot"
|
||||||
|
reload_animation = "blasterM_Reload"
|
||||||
|
change_animation = "blasterM_Deactive"
|
||||||
|
drop_animation = "blasterM_Drop"
|
||||||
|
out_of_ammo_animation = "blasterM_OOA"
|
||||||
|
melee_animation = "blasterM_Melee"
|
||||||
|
has_ammo = true
|
||||||
|
magazine = 9
|
||||||
|
max_ammo = 36
|
||||||
|
damage = 5
|
||||||
|
melee_damage = 1.0
|
||||||
|
auto_fire = true
|
||||||
|
fire_range = 50
|
||||||
|
can_be_dropped = true
|
||||||
|
weapon_drop = ExtResource("3_5hojr")
|
||||||
|
weapon_spray = ExtResource("4_5jfrh")
|
||||||
|
projectile_to_load = ExtResource("1_qi0jo")
|
||||||
|
incremental_reload = true
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
[gd_resource type="Resource" script_class="WeaponResource" format=3 uid="uid://c1jg0ifn7yvve"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://ca7h24lxxrtvx" path="res://client/template/scripts/Weapon_State_Machine/weapon_resource.gd" id="1_oxrhl"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://dc48o4niy1mok" path="res://client/template/Spawnable_Objects/Projectiles_To_Load/basic_hitscan_projectile.tscn" id="1_xr7bm"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://gtthejj2wmyj" path="res://client/template/Spawnable_Objects/Weapons/blaster_n.tscn" id="3_c38hr"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://3mb12hvruajh" path="res://client/template/Spawnable_Objects/SprayProfiles/spray_profile_2.tscn" id="4_rk8dx"]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
script = ExtResource("1_oxrhl")
|
||||||
|
weapon_name = "blaster_n"
|
||||||
|
pick_up_animation = "Global/blasterN Active"
|
||||||
|
shoot_animation = "Global/blasterN Shoot"
|
||||||
|
reload_animation = "Global/blasterN Reload"
|
||||||
|
change_animation = "Global/blasterN De-Activate"
|
||||||
|
drop_animation = "Global/blasterN Drop"
|
||||||
|
out_of_ammo_animation = "Global/blasterN OOA"
|
||||||
|
melee_animation = "Global/blasterN Melee"
|
||||||
|
magazine = 5
|
||||||
|
max_ammo = 15
|
||||||
|
damage = 1
|
||||||
|
melee_damage = 1.0
|
||||||
|
fire_range = 100
|
||||||
|
can_be_dropped = true
|
||||||
|
weapon_drop = ExtResource("3_c38hr")
|
||||||
|
weapon_spray = ExtResource("4_rk8dx")
|
||||||
|
projectile_to_load = ExtResource("1_xr7bm")
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
[gd_resource type="Resource" script_class="WeaponResource" load_steps=4 format=3 uid="uid://dgayjkjx4mckc"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://ca7h24lxxrtvx" path="res://client/template/scripts/Weapon_State_Machine/weapon_resource.gd" id="1_321c1"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://ddfiivxgnakti" path="res://client/template/Spawnable_Objects/Projectiles_To_Load/rocket_launcher_projectile.tscn" id="1_xi5nj"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://dwgt7gwe3gfyy" path="res://client/template/Spawnable_Objects/Weapons/blasterQ.tscn" id="2_kih88"]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
script = ExtResource("1_321c1")
|
||||||
|
weapon_name = "blasterQ"
|
||||||
|
pick_up_animation = "Global/blasterQ Active"
|
||||||
|
shoot_animation = "Global/blasterQ Shoot"
|
||||||
|
reload_animation = "Global/blasterQ Reload"
|
||||||
|
change_animation = "Global/blasterQ Deactivate"
|
||||||
|
drop_animation = "Global/blasterQ Drop"
|
||||||
|
out_of_ammo_animation = "Global/blasterQ OOA"
|
||||||
|
melee_animation = "Global/blasterQ Melee"
|
||||||
|
has_ammo = true
|
||||||
|
magazine = 2
|
||||||
|
max_ammo = 6
|
||||||
|
damage = 20
|
||||||
|
melee_damage = 2.0
|
||||||
|
auto_fire = false
|
||||||
|
fire_range = 100
|
||||||
|
can_be_dropped = true
|
||||||
|
weapon_drop = ExtResource("2_kih88")
|
||||||
|
projectile_to_load = ExtResource("1_xi5nj")
|
||||||
|
incremental_reload = false
|
||||||
@@ -0,0 +1,263 @@
|
|||||||
|
extends Node3D
|
||||||
|
|
||||||
|
signal weapon_changed
|
||||||
|
signal update_ammo
|
||||||
|
signal update_weapon_stack
|
||||||
|
signal hit_successfull
|
||||||
|
signal add_signal_to_hud
|
||||||
|
|
||||||
|
signal connect_weapon_to_hud
|
||||||
|
|
||||||
|
@export var animation_player: AnimationPlayer
|
||||||
|
@export var melee_hitbox: ShapeCast3D
|
||||||
|
@export var max_weapons: int
|
||||||
|
@onready var bullet_point = get_node("%BulletPoint")
|
||||||
|
@onready var debug_bullet = preload("res://client/template/Spawnable_Objects/hit_debug.tscn")
|
||||||
|
|
||||||
|
var next_weapon: WeaponSlot
|
||||||
|
|
||||||
|
#The List of All Available weapons in the game
|
||||||
|
var spray_profiles: Dictionary = {}
|
||||||
|
var _count = 0
|
||||||
|
var shot_tween
|
||||||
|
@export var weapon_stack:Array[WeaponSlot] #An Array of weapons currently in possesion by the player
|
||||||
|
var current_weapon_slot: WeaponSlot = null
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
if weapon_stack.is_empty():
|
||||||
|
push_error("Weapon Stack is empty, please populate with weapons")
|
||||||
|
else:
|
||||||
|
animation_player.animation_finished.connect(_on_animation_finished)
|
||||||
|
for i in weapon_stack:
|
||||||
|
initialize(i) #current starts on the first weapon in the stack
|
||||||
|
current_weapon_slot = weapon_stack[0]
|
||||||
|
if check_valid_weapon_slot():
|
||||||
|
enter()
|
||||||
|
update_weapon_stack.emit(weapon_stack)
|
||||||
|
|
||||||
|
func _unhandled_key_input(event: InputEvent) -> void:
|
||||||
|
if not event.is_pressed():
|
||||||
|
return
|
||||||
|
|
||||||
|
if range(KEY_1, KEY_4).has(event.keycode):
|
||||||
|
var _slot_number = (event.keycode - KEY_1)
|
||||||
|
if weapon_stack.size()-1>=_slot_number:
|
||||||
|
exit(weapon_stack[_slot_number])
|
||||||
|
|
||||||
|
func _input(event: InputEvent) -> void:
|
||||||
|
if event.is_action_pressed("WeaponUp"):
|
||||||
|
if check_valid_weapon_slot():
|
||||||
|
var weapon_index = weapon_stack.find(current_weapon_slot)
|
||||||
|
weapon_index = min(weapon_index+1,weapon_stack.size()-1)
|
||||||
|
exit(weapon_stack[weapon_index])
|
||||||
|
|
||||||
|
if event.is_action_pressed("WeaponDown"):
|
||||||
|
if check_valid_weapon_slot():
|
||||||
|
var weapon_index = weapon_stack.find(current_weapon_slot)
|
||||||
|
weapon_index = max(weapon_index-1,0)
|
||||||
|
exit(weapon_stack[weapon_index])
|
||||||
|
|
||||||
|
if event.is_action_pressed("Shoot"):
|
||||||
|
if check_valid_weapon_slot():
|
||||||
|
shoot()
|
||||||
|
|
||||||
|
if event.is_action_released("Shoot"):
|
||||||
|
if check_valid_weapon_slot():
|
||||||
|
shot_count_update()
|
||||||
|
|
||||||
|
if event.is_action_pressed("Reload"):
|
||||||
|
if check_valid_weapon_slot():
|
||||||
|
reload()
|
||||||
|
|
||||||
|
if event.is_action_pressed("Drop_Weapon"):
|
||||||
|
if check_valid_weapon_slot():
|
||||||
|
drop(current_weapon_slot)
|
||||||
|
|
||||||
|
if event.is_action_pressed("Melee"):
|
||||||
|
if check_valid_weapon_slot():
|
||||||
|
melee()
|
||||||
|
|
||||||
|
func check_valid_weapon_slot()->bool:
|
||||||
|
if current_weapon_slot:
|
||||||
|
if current_weapon_slot.weapon:
|
||||||
|
return true
|
||||||
|
else:
|
||||||
|
push_warning("No Weapon Resource active on the weapon controler.")
|
||||||
|
else:
|
||||||
|
push_warning("No Current Weapon slot active on the weapon controler.")
|
||||||
|
return false
|
||||||
|
|
||||||
|
func initialize(_weapon_slot: WeaponSlot):
|
||||||
|
if !_weapon_slot or !_weapon_slot.weapon:
|
||||||
|
return
|
||||||
|
if _weapon_slot.weapon.weapon_spray:
|
||||||
|
spray_profiles[_weapon_slot.weapon.weapon_name] = _weapon_slot.weapon.weapon_spray.instantiate()
|
||||||
|
connect_weapon_to_hud.emit(_weapon_slot.weapon)
|
||||||
|
|
||||||
|
func enter() -> void:
|
||||||
|
animation_player.queue(current_weapon_slot.weapon.pick_up_animation)
|
||||||
|
weapon_changed.emit(current_weapon_slot.weapon.weapon_name)
|
||||||
|
update_ammo.emit([current_weapon_slot.current_ammo, current_weapon_slot.reserve_ammo])
|
||||||
|
|
||||||
|
func exit(_next_weapon: WeaponSlot) -> void:
|
||||||
|
if _next_weapon != current_weapon_slot:
|
||||||
|
if animation_player.get_current_animation() != current_weapon_slot.weapon.change_animation:
|
||||||
|
animation_player.queue(current_weapon_slot.weapon.change_animation)
|
||||||
|
next_weapon = _next_weapon
|
||||||
|
|
||||||
|
func change_weapon(weapon_slot: WeaponSlot) -> void:
|
||||||
|
current_weapon_slot = weapon_slot
|
||||||
|
next_weapon = null
|
||||||
|
enter()
|
||||||
|
|
||||||
|
func shot_count_update() -> void:
|
||||||
|
shot_tween = get_tree().create_tween()
|
||||||
|
shot_tween.tween_property(self,"_count",0,1)
|
||||||
|
|
||||||
|
func shoot() -> void:
|
||||||
|
if current_weapon_slot.current_ammo != 0 or not current_weapon_slot.weapon.has_ammo:
|
||||||
|
if current_weapon_slot.weapon.incremental_reload and animation_player.current_animation == current_weapon_slot.weapon.reload_animation:
|
||||||
|
animation_player.stop()
|
||||||
|
|
||||||
|
if not animation_player.is_playing():
|
||||||
|
animation_player.play(current_weapon_slot.weapon.shoot_animation)
|
||||||
|
if current_weapon_slot.weapon.has_ammo:
|
||||||
|
current_weapon_slot.current_ammo -= 1
|
||||||
|
|
||||||
|
update_ammo.emit([current_weapon_slot.current_ammo, current_weapon_slot.reserve_ammo])
|
||||||
|
|
||||||
|
if shot_tween:
|
||||||
|
shot_tween.kill()
|
||||||
|
|
||||||
|
var Spread = Vector2.ZERO
|
||||||
|
|
||||||
|
if current_weapon_slot.weapon.weapon_spray:
|
||||||
|
_count = _count + 1
|
||||||
|
Spread = spray_profiles[current_weapon_slot.weapon.weapon_name].Get_Spray(_count, current_weapon_slot.weapon.magazine)
|
||||||
|
|
||||||
|
load_projectile(Spread)
|
||||||
|
else:
|
||||||
|
reload()
|
||||||
|
|
||||||
|
func load_projectile(_spread):
|
||||||
|
var _projectile:Projectile = current_weapon_slot.weapon.projectile_to_load.instantiate()
|
||||||
|
|
||||||
|
_projectile.position = bullet_point.global_position
|
||||||
|
_projectile.rotation = owner.rotation
|
||||||
|
|
||||||
|
bullet_point.add_child(_projectile)
|
||||||
|
add_signal_to_hud.emit(_projectile)
|
||||||
|
var bullet_point_origin = bullet_point.global_position
|
||||||
|
_projectile._Set_Projectile(current_weapon_slot.weapon.damage,_spread,current_weapon_slot.weapon.fire_range, bullet_point_origin)
|
||||||
|
|
||||||
|
func reload() -> void:
|
||||||
|
if current_weapon_slot.current_ammo == current_weapon_slot.weapon.magazine:
|
||||||
|
return
|
||||||
|
elif not animation_player.is_playing():
|
||||||
|
if current_weapon_slot.reserve_ammo != 0:
|
||||||
|
animation_player.queue(current_weapon_slot.weapon.reload_animation)
|
||||||
|
else:
|
||||||
|
animation_player.queue(current_weapon_slot.weapon.out_of_ammo_animation)
|
||||||
|
|
||||||
|
func calculate_reload() -> void:
|
||||||
|
if current_weapon_slot.current_ammo == current_weapon_slot.weapon.magazine:
|
||||||
|
var anim_legnth = animation_player.get_current_animation_length()
|
||||||
|
animation_player.advance(anim_legnth)
|
||||||
|
return
|
||||||
|
|
||||||
|
var Mag_Amount = current_weapon_slot.weapon.magazine
|
||||||
|
|
||||||
|
if current_weapon_slot.weapon.incremental_reload:
|
||||||
|
Mag_Amount = current_weapon_slot.current_ammo+1
|
||||||
|
|
||||||
|
var Reload_Amount = min(Mag_Amount-current_weapon_slot.current_ammo,Mag_Amount,current_weapon_slot.reserve_ammo)
|
||||||
|
|
||||||
|
current_weapon_slot.current_ammo = current_weapon_slot.current_ammo+Reload_Amount
|
||||||
|
current_weapon_slot.reserve_ammo = current_weapon_slot.reserve_ammo-Reload_Amount
|
||||||
|
|
||||||
|
update_ammo.emit([current_weapon_slot.current_ammo, current_weapon_slot.reserve_ammo])
|
||||||
|
shot_count_update()
|
||||||
|
|
||||||
|
func melee() -> void:
|
||||||
|
var Current_Anim = animation_player.get_current_animation()
|
||||||
|
|
||||||
|
if Current_Anim == current_weapon_slot.weapon.shoot_animation:
|
||||||
|
return
|
||||||
|
|
||||||
|
if Current_Anim != current_weapon_slot.weapon.melee_animation:
|
||||||
|
animation_player.play(current_weapon_slot.weapon.melee_animation)
|
||||||
|
if melee_hitbox.is_colliding():
|
||||||
|
var colliders = melee_hitbox.get_collision_count()
|
||||||
|
for c in colliders:
|
||||||
|
var Target = melee_hitbox.get_collider(c)
|
||||||
|
if Target.is_in_group("Target") and Target.has_method("Hit_Successful"):
|
||||||
|
hit_successfull.emit()
|
||||||
|
var Direction = (Target.global_transform.origin - owner.global_transform.origin).normalized()
|
||||||
|
var Position = melee_hitbox.get_collision_point(c)
|
||||||
|
Target.Hit_Successful(current_weapon_slot.weapon.melee_damage, Direction, Position)
|
||||||
|
|
||||||
|
func drop(_slot: WeaponSlot) -> void:
|
||||||
|
if _slot.weapon.can_be_dropped and weapon_stack.size() != 1:
|
||||||
|
var weapon_index = weapon_stack.find(_slot,0)
|
||||||
|
if weapon_index != -1:
|
||||||
|
weapon_stack.pop_at(weapon_index)
|
||||||
|
update_weapon_stack.emit(weapon_stack)
|
||||||
|
|
||||||
|
if _slot.weapon.weapon_drop:
|
||||||
|
var weapon_dropped = _slot.weapon.weapon_drop.instantiate()
|
||||||
|
weapon_dropped.weapon = _slot
|
||||||
|
weapon_dropped.set_global_transform(bullet_point.get_global_transform())
|
||||||
|
get_tree().get_root().add_child(weapon_dropped)
|
||||||
|
|
||||||
|
animation_player.play(current_weapon_slot.weapon.drop_animation)
|
||||||
|
weapon_index = max(weapon_index-1,0)
|
||||||
|
exit(weapon_stack[weapon_index])
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
|
||||||
|
func _on_animation_finished(anim_name):
|
||||||
|
if anim_name == current_weapon_slot.weapon.shoot_animation:
|
||||||
|
if current_weapon_slot.weapon.auto_fire == true:
|
||||||
|
if Input.is_action_pressed("Shoot"):
|
||||||
|
shoot()
|
||||||
|
|
||||||
|
if anim_name == current_weapon_slot.weapon.change_animation:
|
||||||
|
change_weapon(next_weapon)
|
||||||
|
|
||||||
|
if anim_name == current_weapon_slot.weapon.reload_animation:
|
||||||
|
if !current_weapon_slot.weapon.incremental_reload:
|
||||||
|
calculate_reload()
|
||||||
|
|
||||||
|
func _on_pick_up_detection_body_entered(body: RigidBody3D):
|
||||||
|
var weapon_slot = body.weapon
|
||||||
|
for slot in weapon_stack:
|
||||||
|
if slot.weapon == weapon_slot.weapon:
|
||||||
|
var remaining
|
||||||
|
|
||||||
|
remaining = add_ammo(slot, weapon_slot.current_ammo+weapon_slot.reserve_ammo)
|
||||||
|
weapon_slot.current_ammo = min(remaining, slot.weapon.magazine)
|
||||||
|
weapon_slot.reserve_ammo = max(remaining - weapon_slot.current_ammo,0)
|
||||||
|
|
||||||
|
if remaining == 0:
|
||||||
|
body.queue_free()
|
||||||
|
return
|
||||||
|
|
||||||
|
if body.TYPE == "Weapon":
|
||||||
|
if weapon_stack.size() == max_weapons:
|
||||||
|
return
|
||||||
|
|
||||||
|
if body.Pick_Up_Ready == true:
|
||||||
|
var weapon_index = weapon_stack.find(current_weapon_slot)
|
||||||
|
weapon_stack.insert(weapon_index,weapon_slot)
|
||||||
|
update_weapon_stack.emit(weapon_stack)
|
||||||
|
exit(weapon_slot)
|
||||||
|
initialize(weapon_slot)
|
||||||
|
body.queue_free()
|
||||||
|
|
||||||
|
func add_ammo(_weapon_slot: WeaponSlot, ammo: int)->int:
|
||||||
|
var weapon = _weapon_slot.weapon
|
||||||
|
var required = weapon.max_ammo - _weapon_slot.reserve_ammo
|
||||||
|
var remaining = max(ammo - required,0)
|
||||||
|
_weapon_slot.reserve_ammo += min(ammo, required)
|
||||||
|
update_ammo.emit([current_weapon_slot.current_ammo, current_weapon_slot.reserve_ammo])
|
||||||
|
return remaining
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://cxxpp8cfxb8jp
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
extends RigidBody3D
|
||||||
|
|
||||||
|
signal Hit_Successfull
|
||||||
|
|
||||||
|
var damage: int = 0
|
||||||
|
|
||||||
|
func _on_body_entered(body):
|
||||||
|
if body.is_in_group("Target") && body.has_method("Hit_Successful"):
|
||||||
|
body.Hit_Successful(damage)
|
||||||
|
emit_signal("Hit_Successfull")
|
||||||
|
|
||||||
|
queue_free()
|
||||||
|
|
||||||
|
func _on_timer_timeout():
|
||||||
|
queue_free()
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
uid://11gya5082xv3
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
extends Sprite3D
|
||||||
|
|
||||||
|
func _on_timer_timeout():
|
||||||
|
queue_free()
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user