214 lines
9.3 KiB
GDScript
214 lines
9.3 KiB
GDScript
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
|