220 lines
11 KiB
GDScript
220 lines
11 KiB
GDScript
class_name WeaponModels
|
||||
|
|
extends RefCounted
|
|||
|
|
|
|||
|
|
const G = preload("res://scripts/weapon_geometry.gd")
|
|||
|
|
static var cache := {}
|
|||
|
|
static var muzzle_points := {}
|
|||
|
|
|
|||
|
|
static func build(index: int) -> Node3D:
|
|||
|
|
if StylooWeapons.MODELS.has(index):
|
|||
|
|
var imported := StylooWeapons.build(index)
|
|||
|
|
muzzle_points[index] = imported.get_node("Muzzle").position
|
|||
|
|
return imported
|
|||
|
|
if SovietWeapons.MODELS.has(index):
|
|||
|
|
var imported := SovietWeapons.build(index)
|
|||
|
|
muzzle_points[index] = imported.get_node("Muzzle").position
|
|||
|
|
return imported
|
|||
|
|
if cache.has(index):
|
|||
|
|
return cache[index].instantiate()
|
|||
|
|
var root := Node3D.new()
|
|||
|
|
root.name = "WeaponModel"
|
|||
|
|
root.set_meta("weapon_index", index)
|
|||
|
|
var frame := Node3D.new()
|
|||
|
|
frame.name = "Frame"
|
|||
|
|
root.add_child(frame)
|
|||
|
|
var magazine := Node3D.new()
|
|||
|
|
magazine.name = "Magazine"
|
|||
|
|
root.add_child(magazine)
|
|||
|
|
var bolt := Node3D.new()
|
|||
|
|
bolt.name = "Bolt"
|
|||
|
|
root.add_child(bolt)
|
|||
|
|
match Arsenal.FAMILIES[index]:
|
|||
|
|
0: rifle(frame, magazine, bolt)
|
|||
|
|
1: smg(frame, magazine, bolt)
|
|||
|
|
2: shotgun(frame, magazine, bolt)
|
|||
|
|
3: sniper(frame, magazine, bolt)
|
|||
|
|
4: pistol(frame, magazine, bolt)
|
|||
|
|
WeaponVariants.decorate(index, frame, magazine)
|
|||
|
|
var muzzle := Marker3D.new()
|
|||
|
|
muzzle.name = "Muzzle"
|
|||
|
|
muzzle.position = frame.get_meta("muzzle")
|
|||
|
|
root.add_child(muzzle)
|
|||
|
|
muzzle_points[index] = muzzle.position
|
|||
|
|
WeaponSkins.split_frame(frame)
|
|||
|
|
G.batch(magazine)
|
|||
|
|
G.batch(bolt)
|
|||
|
|
assign_owner(root, root)
|
|||
|
|
var scene := PackedScene.new()
|
|||
|
|
scene.pack(root)
|
|||
|
|
cache[index] = scene
|
|||
|
|
return root
|
|||
|
|
|
|||
|
|
static func assign_owner(node: Node, owner_node: Node) -> void:
|
|||
|
|
for child in node.get_children():
|
|||
|
|
child.owner = owner_node
|
|||
|
|
assign_owner(child, owner_node)
|
|||
|
|
|
|||
|
|
static func grip(parent: Node3D, z: float, key: String = "polymer") -> void:
|
|||
|
|
G.profile(parent, PackedVector2Array([Vector2(z - 0.025, -0.03), Vector2(z + 0.03, -0.045),
|
|||
|
|
Vector2(z + 0.082, -0.18), Vector2(z + 0.027, -0.192), Vector2(z - 0.017, -0.10)]), 0.044, Vector3.ZERO, key)
|
|||
|
|
for i in 7:
|
|||
|
|
G.block(parent, Vector3(0, -0.091 - i * 0.012, z + 0.035 + i * 0.004), Vector3(0.046, 0.003, 0.045), "rubber", Vector3(-0.32, 0, 0))
|
|||
|
|
# Open trigger guard, curved trigger and a safety lever.
|
|||
|
|
G.block(parent, Vector3(0, -0.094, z - 0.038), Vector3(0.015, 0.008, 0.073), "black")
|
|||
|
|
G.block(parent, Vector3(0, -0.066, z - 0.07), Vector3(0.015, 0.06, 0.008), "black")
|
|||
|
|
G.block(parent, Vector3(0, -0.065, z - 0.034), Vector3(0.009, 0.035, 0.009), "silver", Vector3(0.3, 0, 0))
|
|||
|
|
|
|||
|
|
static func stock(parent: Node3D, key: String, precision: bool = false) -> void:
|
|||
|
|
G.tube(parent, Vector3(0, 0, 0.12), 0.019, 0.2, "steel")
|
|||
|
|
G.profile(parent, PackedVector2Array([Vector2(0.07, 0.026), Vector2(0.32, 0.033),
|
|||
|
|
Vector2(0.34, -0.11), Vector2(0.28, -0.115), Vector2(0.18, -0.052), Vector2(0.07, -0.024)]), 0.06, Vector3.ZERO, key)
|
|||
|
|
G.block(parent, Vector3(0, -0.043, 0.34), Vector3(0.067, 0.148, 0.022), "rubber")
|
|||
|
|
G.block(parent, Vector3(0, 0.035, 0.24), Vector3(0.064, 0.025, 0.135), "polymer")
|
|||
|
|
for z in [0.17, 0.23, 0.29]:
|
|||
|
|
G.screw(parent, Vector3(0.034, -0.035, z))
|
|||
|
|
if precision:
|
|||
|
|
G.block(parent, Vector3(0, 0.065, 0.23), Vector3(0.06, 0.035, 0.14), "rubber")
|
|||
|
|
G.tube(parent, Vector3(0.048, -0.065, 0.23), 0.017, 0.018, "edge", Vector3(0, 0, PI / 2))
|
|||
|
|
|
|||
|
|
static func barrel(parent: Node3D, z: float, length: float, radius: float = 0.011) -> void:
|
|||
|
|
G.tube(parent, Vector3(0, 0.016, z), radius, length, "steel")
|
|||
|
|
var tip := z - length / 2
|
|||
|
|
parent.set_meta("muzzle", Vector3(0, 0.016, tip - 0.042))
|
|||
|
|
G.tube(parent, Vector3(0, 0.016, tip - 0.018), radius * 1.6, 0.044, "black")
|
|||
|
|
G.tube(parent, Vector3(0, 0.016, tip - 0.041), radius * 0.76, 0.002, "rubber")
|
|||
|
|
for i in 3:
|
|||
|
|
G.block(parent, Vector3(radius * 1.6, 0.016, tip - 0.004 - i * 0.012), Vector3(0.002, 0.014, 0.006), "rubber")
|
|||
|
|
|
|||
|
|
static func optic(parent: Node3D, z: float, scope: bool = false) -> void:
|
|||
|
|
# Keep replaceable optics separate from rails, carry handles and receiver parts.
|
|||
|
|
var mount := Node3D.new()
|
|||
|
|
mount.name = "FactoryOptic"
|
|||
|
|
parent.add_child(mount)
|
|||
|
|
parent = mount
|
|||
|
|
if scope:
|
|||
|
|
for at in [z - 0.075, z + 0.06]:
|
|||
|
|
G.block(parent, Vector3(0, 0.077, at), Vector3(0.042, 0.032, 0.027), "steel")
|
|||
|
|
G.tube(parent, Vector3(0, 0.108, at), 0.027, 0.017, "edge")
|
|||
|
|
G.tube(parent, Vector3(0, 0.108, z), 0.022, 0.27, "black")
|
|||
|
|
G.tube(parent, Vector3(0, 0.108, z - 0.165), 0.035, 0.065, "black", Vector3(PI / 2, 0, 0), 0.022)
|
|||
|
|
G.tube(parent, Vector3(0, 0.108, z + 0.155), 0.032, 0.05, "rubber")
|
|||
|
|
G.tube(parent, Vector3(0, 0.108, z + 0.181), 0.025, 0.001, "glass")
|
|||
|
|
G.tube(parent, Vector3(0, 0.145, z), 0.018, 0.023, "edge", Vector3.ZERO)
|
|||
|
|
G.tube(parent, Vector3(0.032, 0.108, z), 0.018, 0.023, "edge", Vector3(0, 0, PI / 2))
|
|||
|
|
for i in 14:
|
|||
|
|
var angle := i * TAU / 14
|
|||
|
|
G.block(parent, Vector3(sin(angle) * 0.033, 0.108 + cos(angle) * 0.033, z + 0.14), Vector3(0.004, 0.005, 0.028), "edge", Vector3(0, 0, -angle))
|
|||
|
|
else:
|
|||
|
|
G.block(parent, Vector3(0, 0.077, z), Vector3(0.047, 0.022, 0.065), "black")
|
|||
|
|
for side in [-1, 1]:
|
|||
|
|
G.block(parent, Vector3(side * 0.023, 0.11, z), Vector3(0.007, 0.046, 0.022), "edge")
|
|||
|
|
G.block(parent, Vector3(0, 0.134, z), Vector3(0.047, 0.007, 0.022), "edge")
|
|||
|
|
G.block(parent, Vector3(0, 0.11, z + 0.012), Vector3(0.0015, 0.0015, 0.001), "red")
|
|||
|
|
|
|||
|
|
static func magazine(parent: Node3D, z: float, length: float, key: String, curve: float = 0.025) -> void:
|
|||
|
|
G.profile(parent, PackedVector2Array([Vector2(z - 0.035, -0.035), Vector2(z + 0.035, -0.035),
|
|||
|
|
Vector2(z + 0.035 + curve, -length), Vector2(z - 0.032 + curve, -length - 0.012)]), 0.043, Vector3.ZERO, key)
|
|||
|
|
for side in [-1, 1]:
|
|||
|
|
for rib in 3:
|
|||
|
|
G.block(parent, Vector3(side * 0.023, -length * 0.6, z - 0.022 + rib * 0.02 + curve / 2), Vector3(0.003, length * 0.6, 0.004), "black", Vector3(-curve * 2, 0, 0))
|
|||
|
|
G.block(parent, Vector3(0, -length, z + curve), Vector3(0.051, 0.015, 0.077), "rubber")
|
|||
|
|
|
|||
|
|
static func rifle(frame: Node3D, mag: Node3D, bolt: Node3D) -> void:
|
|||
|
|
G.block(frame, Vector3(0, 0, -0.075), Vector3(0.069, 0.085, 0.225), "steel")
|
|||
|
|
G.block(frame, Vector3(0, -0.038, -0.055), Vector3(0.062, 0.045, 0.19), "black")
|
|||
|
|
G.block(frame, Vector3(0, 0.005, -0.305), Vector3(0.075, 0.075, 0.245), "sand")
|
|||
|
|
for side in [-1, 1]:
|
|||
|
|
for i in 7:
|
|||
|
|
G.block(frame, Vector3(side * 0.038, 0.004, -0.22 - i * 0.026), Vector3(0.002, 0.018, 0.016), "black")
|
|||
|
|
for z in [-0.04, -0.14, -0.2, -0.4]:
|
|||
|
|
G.screw(frame, Vector3(side * 0.04, -0.022, z))
|
|||
|
|
barrel(frame, -0.46, 0.12)
|
|||
|
|
stock(frame, "sand")
|
|||
|
|
grip(frame, 0.015)
|
|||
|
|
magazine(mag, -0.115, 0.2, "sand")
|
|||
|
|
G.block(bolt, Vector3(0.036, 0.006, -0.09), Vector3(0.004, 0.024, 0.065), "silver")
|
|||
|
|
G.block(frame, Vector3(0.04, -0.025, -0.09), Vector3(0.007, 0.012, 0.066), "black")
|
|||
|
|
G.rail(frame, 0.015, -0.43, 0.047)
|
|||
|
|
optic(frame, -0.06)
|
|||
|
|
G.label(frame, "KESTREL / AR-4\n5.56 • BL-0427", Vector3(0.036, -0.014, -0.04), 26)
|
|||
|
|
|
|||
|
|
static func smg(frame: Node3D, mag: Node3D, bolt: Node3D) -> void:
|
|||
|
|
G.profile(frame, PackedVector2Array([Vector2(0.05, 0.037), Vector2(-0.28, 0.037), Vector2(-0.31, -0.01),
|
|||
|
|
Vector2(-0.25, -0.075), Vector2(-0.09, -0.085), Vector2(0.05, -0.04)]), 0.065, Vector3.ZERO, "polymer")
|
|||
|
|
G.block(frame, Vector3(0, 0.018, -0.1), Vector3(0.07, 0.056, 0.27), "black")
|
|||
|
|
grip(frame, 0.01)
|
|||
|
|
magazine(mag, -0.095, 0.25, "steel", 0.008)
|
|||
|
|
barrel(frame, -0.335, 0.09)
|
|||
|
|
for side in [-1, 1]:
|
|||
|
|
G.tube(frame, Vector3(side * 0.025, 0.006, 0.17), 0.007, 0.27, "edge")
|
|||
|
|
G.block(frame, Vector3(0, -0.032, 0.3), Vector3(0.065, 0.11, 0.025), "rubber")
|
|||
|
|
for i in 6:
|
|||
|
|
G.block(frame, Vector3(0.034, -0.015, -0.15 - i * 0.02), Vector3(0.002, 0.019, 0.007), "rubber")
|
|||
|
|
G.block(bolt, Vector3(0.037, 0.015, -0.07), Vector3(0.006, 0.018, 0.06), "silver")
|
|||
|
|
G.rail(frame, 0.01, -0.26, 0.052)
|
|||
|
|
optic(frame, -0.07)
|
|||
|
|
G.label(frame, "VECTOR V9\n9 × 19 / RELAY", Vector3(0.037, -0.033, -0.15), 25)
|
|||
|
|
|
|||
|
|
static func shotgun(frame: Node3D, mag: Node3D, bolt: Node3D) -> void:
|
|||
|
|
G.block(frame, Vector3(0, 0.004, -0.07), Vector3(0.065, 0.085, 0.23), "steel")
|
|||
|
|
stock(frame, "polymer")
|
|||
|
|
grip(frame, 0.015)
|
|||
|
|
barrel(frame, -0.425, 0.49, 0.016)
|
|||
|
|
G.tube(frame, Vector3(0, -0.034, -0.37), 0.015, 0.39, "black")
|
|||
|
|
G.block(bolt, Vector3(0, -0.025, -0.31), Vector3(0.079, 0.069, 0.18), "polymer")
|
|||
|
|
for i in 10:
|
|||
|
|
G.block(bolt, Vector3(0, -0.025, -0.23 - i * 0.017), Vector3(0.083, 0.075, 0.007), "rubber")
|
|||
|
|
G.block(frame, Vector3(0.034, 0.008, -0.065), Vector3(0.004, 0.03, 0.083), "black")
|
|||
|
|
for i in 4:
|
|||
|
|
G.tube(mag, Vector3(-0.047, -0.015, -0.005 - i * 0.025), 0.009, 0.058, "red", Vector3.ZERO)
|
|||
|
|
G.tube(mag, Vector3(-0.047, 0.015, -0.005 - i * 0.025), 0.0095, 0.009, "brass", Vector3.ZERO)
|
|||
|
|
G.rail(frame, 0.015, -0.17, 0.053)
|
|||
|
|
G.block(frame, Vector3(0, 0.047, -0.61), Vector3(0.008, 0.04, 0.014), "steel")
|
|||
|
|
G.tube(frame, Vector3(0, 0.067, -0.61), 0.002, 0.014, "red")
|
|||
|
|
G.label(frame, "BREACH SG-8 / 12 GA", Vector3(0.035, -0.02, -0.06), 25)
|
|||
|
|
|
|||
|
|
static func sniper(frame: Node3D, mag: Node3D, bolt: Node3D) -> void:
|
|||
|
|
G.block(frame, Vector3(0, -0.023, -0.1), Vector3(0.068, 0.054, 0.31), "sand")
|
|||
|
|
G.tube(frame, Vector3(0, 0.021, -0.1), 0.027, 0.3, "steel")
|
|||
|
|
G.block(frame, Vector3(0, 0.005, -0.385), Vector3(0.068, 0.064, 0.26), "sand")
|
|||
|
|
barrel(frame, -0.54, 0.43, 0.013)
|
|||
|
|
stock(frame, "sand", true)
|
|||
|
|
grip(frame, 0.025)
|
|||
|
|
magazine(mag, -0.12, 0.12, "steel", 0)
|
|||
|
|
for i in 8:
|
|||
|
|
G.block(frame, Vector3(0.035, 0, -0.28 - i * 0.027), Vector3(0.002, 0.027, 0.014), "black")
|
|||
|
|
G.rail(frame, 0.025, -0.26, 0.052)
|
|||
|
|
optic(frame, -0.1, true)
|
|||
|
|
G.tube(bolt, Vector3(0.044, 0.022, 0.01), 0.005, 0.056, "silver", Vector3(0, 0, PI / 2))
|
|||
|
|
G.tube(bolt, Vector3(0.07, 0.005, 0.01), 0.009, 0.04, "black", Vector3(0, 0, -0.35))
|
|||
|
|
for side in [-1, 1]:
|
|||
|
|
G.tube(frame, Vector3(side * 0.044, -0.051, -0.47), 0.009, 0.15, "black")
|
|||
|
|
G.tube(frame, Vector3(side * 0.044, -0.051, -0.55), 0.013, 0.02, "rubber")
|
|||
|
|
G.label(frame, "LONGSHOT M77\n7.62 / PRECISION SYSTEMS", Vector3(0.036, -0.026, -0.1), 23)
|
|||
|
|
|
|||
|
|
static func pistol(frame: Node3D, mag: Node3D, bolt: Node3D) -> void:
|
|||
|
|
frame.set_meta("muzzle", Vector3(0, 0.036, -0.192))
|
|||
|
|
G.profile(frame, PackedVector2Array([Vector2(0.065, 0.01), Vector2(-0.18, 0.01), Vector2(-0.18, -0.04),
|
|||
|
|
Vector2(-0.055, -0.05), Vector2(0.015, -0.075), Vector2(0.064, -0.055)]), 0.033, Vector3.ZERO, "polymer")
|
|||
|
|
G.block(bolt, Vector3(0, 0.036, -0.058), Vector3(0.035, 0.044, 0.25), "steel")
|
|||
|
|
G.tube(frame, Vector3(0, 0.036, -0.075), 0.009, 0.23, "silver")
|
|||
|
|
G.tube(frame, Vector3(0, 0.036, -0.191), 0.006, 0.002, "rubber")
|
|||
|
|
grip(frame, 0.017)
|
|||
|
|
G.block(mag, Vector3(0, -0.185, 0.073), Vector3(0.047, 0.016, 0.059), "rubber")
|
|||
|
|
for side in [-1, 1]:
|
|||
|
|
for i in 7:
|
|||
|
|
G.block(bolt, Vector3(side * 0.018, 0.037, 0.043 - i * 0.008), Vector3(0.002, 0.035, 0.003), "black", Vector3(-0.15, 0, 0))
|
|||
|
|
for x in [-0.012, 0.012]:
|
|||
|
|
G.block(bolt, Vector3(x, 0.065, 0.05), Vector3(0.009, 0.016, 0.015), "black")
|
|||
|
|
G.block(bolt, Vector3(x, 0.067, 0.058), Vector3(0.003, 0.003, 0.001), "mark")
|
|||
|
|
G.block(bolt, Vector3(0, 0.065, -0.163), Vector3(0.006, 0.013, 0.011), "black")
|
|||
|
|
G.block(bolt, Vector3(0, 0.072, -0.157), Vector3(0.002, 0.002, 0.004), "red")
|
|||
|
|
G.block(bolt, Vector3(0.018, 0.039, -0.048), Vector3(0.002, 0.021, 0.035), "silver")
|
|||
|
|
G.label(bolt, "P12 / 9×19", Vector3(0.019, 0.04, -0.11), 23)
|
|||
|
|
|
|||
|
|
static func muzzle_position(index: int) -> Vector3:
|
|||
|
|
if not muzzle_points.has(index):
|
|||
|
|
var model := build(index)
|
|||
|
|
model.free()
|
|||
|
|
return muzzle_points[index]
|