Files

220 lines
11 KiB
GDScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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]