Files
Blockline/scripts/loadout_overview.gd
T

214 lines
9.3 KiB
GDScript
Raw 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 LoadoutOverview
extends Control
const CYAN := Color("86bfd0")
var editor: ClassEditor
var layout := Control.new()
var classes := VBoxContainer.new()
var primary: Button
var pistol: Button
var bench: WeaponShowcase
var thumbnails: Array[WeaponShowcase] = []
var weapon_names: Array[Label] = []
var attachment_labels: Array[Label] = []
var feedback: Label
var sidearm: Node3D
func text(value: String, at: Vector2, font_size: int, color: Color = Color("a7a8a4")) -> Label:
var label := Label.new()
label.text = value
label.position = at
label.add_theme_font_size_override("font_size", font_size)
label.add_theme_color_override("font_color", color)
layout.add_child(label)
return label
func tile(value: String, at: Vector2, dimensions: Vector2, callback: Callable) -> Button:
var button := Button.new()
button.text = value
button.position = at
button.size = dimensions
button.alignment = HORIZONTAL_ALIGNMENT_LEFT
button.add_theme_font_size_override("font_size", 19)
button.add_theme_color_override("font_color", Color("969b9b"))
button.add_theme_color_override("font_hover_color", CYAN)
button.add_theme_color_override("font_focus_color", CYAN)
for state: String in ["normal", "hover", "pressed", "focus"]:
var style := StyleBoxFlat.new()
style.bg_color = Color(0.065, 0.066, 0.068, 0.92) if state == "normal" else Color(0.09, 0.13, 0.145, 0.97)
style.border_width_top = 0 if state == "normal" else 1
style.border_color = CYAN
style.content_margin_left = 18
button.add_theme_stylebox_override(state, style)
button.pressed.connect(callback)
layout.add_child(button)
return button
func _ready() -> void:
set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
add_child(layout)
layout.mouse_filter = Control.MOUSE_FILTER_IGNORE
resized.connect(func(): layout.scale = size / Vector2(1600, 900))
layout.scale = size / Vector2(1600, 900)
bench = WeaponShowcase.new()
layout.add_child(bench)
bench.position = Vector2(680, 85)
bench.size = Vector2(920, 750)
bench.stretch = true
bench.mouse_filter = Control.MOUSE_FILTER_IGNORE
var environment := bench.stage.get_child(0) as WorldEnvironment
environment.environment.background_color = Color("050707")
environment.environment.ambient_light_energy = 0.18
for child in bench.stage.get_children():
if child is OmniLight3D:
child.light_energy = 1.1
child.shadow_enabled = true
make_bench()
text("EDIT LOADOUTS", Vector2(77, 33), 38, Color("6e959f"))
text(editor.ui.game.nickname + " / LOCAL OPERATOR", Vector2(1150, 47), 16)
var scroll := ScrollContainer.new()
scroll.position = Vector2(80, 142)
scroll.size = Vector2(308, 280)
layout.add_child(scroll)
classes.size_flags_horizontal = Control.SIZE_EXPAND_FILL
classes.add_theme_constant_override("separation", 7)
scroll.add_child(classes)
primary = tile("", Vector2(445, 142), Vector2(337, 158), func(): open_weapon(false))
pistol = tile("", Vector2(445, 310), Vector2(337, 158), func(): open_weapon(true))
for index in 2:
var card: Button = primary if index == 0 else pistol
var heading := text("Primary Weapon" if index == 0 else "Secondary Weapon", Vector2.ZERO, 18)
heading.reparent(card, false)
heading.position = Vector2(18, 8)
heading.mouse_filter = Control.MOUSE_FILTER_IGNORE
var weapon_name := text("", Vector2.ZERO, 13)
weapon_name.reparent(card, false)
weapon_name.position = Vector2(18, 33)
weapon_names.append(weapon_name)
var dots := text("", Vector2.ZERO, 16, Color("9f7639"))
dots.reparent(card, false)
dots.position = Vector2(235, 10)
attachment_labels.append(dots)
var thumbnail := WeaponShowcase.new()
card.add_child(thumbnail)
thumbnail.position = Vector2(62, 52)
thumbnail.size = Vector2(220, 77)
thumbnail.stretch = true
thumbnail.mouse_filter = Control.MOUSE_FILTER_IGNORE
var env := thumbnail.stage.get_child(0) as WorldEnvironment
env.environment.background_color = Color("101112")
thumbnails.append(thumbnail)
var caption := text("ANPASSEN / WAFFENSCHMIED", Vector2.ZERO, 11, Color("626969"))
caption.reparent(card, false)
caption.position = Vector2(18, 139)
tile("Ausrüstung\n\n◈ ENERGIESCHILD ✦ CLAYMORE", Vector2(445, 480), Vector2(337, 100), func(): editor.notice.text = "Ausrüstung ist für alle Klassen festgelegt.")
tile("Lethal\n\nFrag-Granate × 2", Vector2(445, 590), Vector2(337, 73), func(): editor.notice.text = "Zwei Frag-Granaten pro Leben.")
tile("Tactical\n\nFlashbang × 1", Vector2(445, 675), Vector2(337, 73), func(): editor.notice.text = "Eine Flashbang pro Leben.")
tile("KLASSENOPTIONEN / VORLAGEN", Vector2(80, 690), Vector2(308, 40), func(): editor.show_workshop())
tile("SPEICHERN & AUSRÜSTEN", Vector2(80, 741), Vector2(308, 40), editor.save_class)
tile("← BACK", Vector2(80, 843), Vector2(160, 36), editor.ui.main_menu)
text("AUSWÄHLEN / WAFFE ANPASSEN", Vector2(270, 853), 14)
feedback = text("Änderungen gelten ab dem nächsten Spawn.", Vector2(820, 853), 13)
feedback.size = Vector2(700, 35)
feedback.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS
refresh()
func box(at: Vector3, dimensions: Vector3, color: Color) -> MeshInstance3D:
var node := MeshInstance3D.new()
var mesh := BoxMesh.new()
mesh.size = dimensions
node.mesh = mesh
var material := StandardMaterial3D.new()
material.albedo_color = color
material.roughness = 0.84
node.material_override = material
node.position = at
bench.stage.add_child(node)
return node
func make_bench() -> void:
var tabletop := box(Vector3(0, -0.19, -0.1), Vector3(1.3, 0.09, 1.7), Color("242a2b"))
var surface := tabletop.material_override as StandardMaterial3D
surface.albedo_texture = load("res://assets/materials/concrete_color.jpg")
surface.normal_enabled = true
surface.normal_texture = load("res://assets/materials/concrete_normal.jpg")
surface.uv1_scale = Vector3(2, 2, 2)
var pad := box(Vector3(0, -0.13, -0.15), Vector3(0.54, 0.06, 0.91), Color("121616"))
pad.rotation.y = -0.2
for index in 10:
var seam := box(Vector3(-0.23 + index * 0.05, -0.097, -0.15), Vector3(0.003, 0.005, 0.84), Color("252a28"))
seam.rotation.y = -0.2
sidearm = WeaponModels.build(4)
bench.stage.add_child(sidearm)
sidearm.position = Vector3(0.39, -0.06, 0.43)
sidearm.rotation = Vector3(0, -0.65, PI / 2)
for index in 18:
var shell := box(Vector3(sin(index * 4.7) * 0.5, -0.125, cos(index * 2.8) * 0.7), Vector3(0.009, 0.009, 0.035), Color("9e8c55"))
shell.rotation.y = index * 1.7
for index in 3:
var bottle := MeshInstance3D.new()
var cylinder := CylinderMesh.new()
cylinder.top_radius = 0.033
cylinder.bottom_radius = 0.038
cylinder.height = 0.19
bottle.mesh = cylinder
bottle.position = Vector3(0.44, -0.025, -0.6 + index * 0.17)
var mat := StandardMaterial3D.new()
mat.albedo_color = Color("303d30")
mat.metallic = 0.45
mat.roughness = 0.45
bottle.material_override = mat
bench.stage.add_child(bottle)
box(bottle.position + Vector3(0, 0.1, 0), Vector3(0.025, 0.02, 0.025), Color("8e918c"))
box(Vector3(-0.4, -0.075, 0.3), Vector3(0.2, 0.15, 0.24), Color("625741"))
box(Vector3(-0.4, 0.003, 0.3), Vector3(0.08, 0.005, 0.035), Color("bfbeb2"))
box(Vector3(-0.4, 0.004, 0.3), Vector3(0.035, 0.005, 0.08), Color("bfbeb2"))
func refresh() -> void:
if not is_instance_valid(primary): return
for child in classes.get_children():
classes.remove_child(child)
child.queue_free()
for index in ClassLoadouts.entries.size():
var button := tile(str(ClassLoadouts.entries[index].name) + (" ★" if index == ClassLoadouts.selected else ""), Vector2.ZERO, Vector2(308, 50), func():
ClassLoadouts.entries[editor.slot] = ClassLoadouts.clean(editor.draft)
editor.slot = index
editor.draft = ClassLoadouts.entries[index].duplicate(true)
editor.refresh())
button.reparent(classes)
button.custom_minimum_size = Vector2(300, 50)
button.text_overrun_behavior = TextServer.OVERRUN_TRIM_ELLIPSIS
button.add_theme_color_override("font_color", CYAN if index == editor.slot else Color("55747e"))
if index == editor.slot: button.grab_focus()
var id := int(editor.draft.primary)
for index in 2:
var weapon_id := id if index == 0 else 4
weapon_names[index].text = Arsenal.DATA[weapon_id].name
var design: Dictionary = editor.draft.skins.get(str(weapon_id), {})
var attachments: Dictionary = design.get("attachments", {})
var count := 0
for value: Variant in attachments.values():
if int(value) != 0: count += 1
attachment_labels[index].text = "●".repeat(count) + "○".repeat(maxi(0, 5 - count))
thumbnails[index].select_weapon(weapon_id)
WeaponSkins.apply(thumbnails[index].model, design)
thumbnails[index].camera.position = Vector3(1.4, 0, -0.15)
thumbnails[index].camera.look_at(Vector3(0, -0.025, -0.15))
thumbnails[index].camera.size = 0.25 if weapon_id == 4 else 0.42
WeaponSkins.apply(sidearm, editor.draft.skins.get("4", {}))
bench.select_weapon(id)
WeaponSkins.apply(bench.model, editor.draft.skins.get(str(id), {}))
bench.model.rotation = Vector3(0, -0.2, PI / 2)
bench.model.position = Vector3(0, -0.025, 0.1)
bench.camera.position = Vector3(1.15, 1.7, 1.1)
bench.camera.look_at(Vector3(0, -0.1, -0.1))
bench.camera.size = 1.75
func open_weapon(is_secondary: bool) -> void:
editor.secondary = is_secondary
editor.refresh()
editor.show_workshop()
func _process(_dt: float) -> void:
if is_instance_valid(feedback): feedback.text = editor.notice.text