Files

181 lines
7.5 KiB
GDScript
Raw Permalink Normal View History

2026-09-12 11:01:37 +02:00
class_name FrontEnd
extends Control
const ORANGE := Color("f18b28")
var ui: GameUI
var loading := false
var status: Label
var progress: ProgressBar
var preview: SubViewport
var actor: ImportedOperator
var elapsed := 0.0
func caption(value: String, at: Vector2, font_size: int, color: Color = Color("cfcbc3")) -> Label:
var item := Label.new()
item.text = value
item.position = at
item.add_theme_font_size_override("font_size", font_size)
item.add_theme_color_override("font_color", color)
add_child(item)
return item
func _ready() -> void:
set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
if DisplayServer.get_name() == "headless":
set_process(false)
return
mouse_filter = Control.MOUSE_FILTER_STOP
resized.connect(queue_redraw)
var backdrop := SubViewportContainer.new()
backdrop.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
backdrop.stretch = true
backdrop.mouse_filter = Control.MOUSE_FILTER_IGNORE
add_child(backdrop)
var viewport := SubViewport.new()
preview = viewport
viewport.own_world_3d = true
viewport.msaa_3d = get_viewport().msaa_3d
viewport.render_target_update_mode = SubViewport.UPDATE_ALWAYS
backdrop.add_child(viewport)
var environment := WorldEnvironment.new()
var env := Environment.new()
env.background_mode = Environment.BG_COLOR
env.background_color = Color("090807")
env.ambient_light_source = Environment.AMBIENT_SOURCE_COLOR
env.ambient_light_color = Color("7c858e")
env.ambient_light_energy = 0.16
env.tonemap_mode = Environment.TONE_MAPPER_FILMIC
environment.environment = env
viewport.add_child(environment)
var camera := Camera3D.new()
viewport.add_child(camera)
camera.position = Vector3(0, 1.38, -1.65)
camera.look_at(Vector3(0.18, 1.35, 0))
camera.fov = 43
camera.current = true
actor = ImportedOperator.new()
viewport.add_child(actor)
actor.setup("gas_mask")
actor.rotation.y = -0.17
actor.preview("pro_rifle__idle", 0.2)
actor.weapon_mount.add_child(WeaponModels.build(0))
for index in 2:
var light := OmniLight3D.new()
light.position = Vector3(-0.7, 2.7, -0.4) if index == 0 else Vector3(1.1, 1.9, 0.7)
light.light_color = Color("ffbe70") if index == 0 else Color("b67b3d")
light.light_energy = 4.0 if index == 0 else 3.0
light.omni_range = 5
viewport.add_child(light)
var veil := TextureRect.new()
var gradient := Gradient.new()
gradient.offsets = PackedFloat32Array([0, 0.25, 0.48, 0.75, 1])
gradient.colors = PackedColorArray([Color(0,0,0,0.88), Color(0,0,0,0.55), Color(0,0,0,0), Color(0,0,0,0.1), Color(0,0,0,0.65)])
var texture := GradientTexture2D.new()
texture.gradient = gradient
texture.fill_from = Vector2(0, 0)
texture.fill_to = Vector2(1, 0)
veil.texture = texture
veil.mouse_filter = Control.MOUSE_FILTER_IGNORE
add_child(veil)
veil.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
var haze := ColorRect.new()
haze.mouse_filter = Control.MOUSE_FILTER_IGNORE
var shader := Shader.new()
shader.code = """shader_type canvas_item;
float noise(vec2 p) { return fract(sin(dot(p,vec2(12.9898,78.233))) * 43758.5453); }
void fragment() {
vec2 p=UV*vec2(20.,12.);
float mist=sin(p.x*.7+TIME*.13)*sin(p.y*.6-TIME*.1);
float glow=exp(-length((UV-vec2(.7,.4))*vec2(2.,1.))*3.);
vec2 sparks=UV*vec2(150.,80.)+vec2(TIME*.6,TIME*1.2);
float dotlight=step(.994,noise(floor(sparks)))*(1.-smoothstep(.02,.13,length(fract(sparks)-.5)));
COLOR=vec4(vec3(.52,.28,.10)+vec3(dotlight),glow*(.06+mist*.025)+dotlight*.65);
}"""
var haze_material := ShaderMaterial.new()
haze_material.shader = shader
haze.material = haze_material
add_child(haze)
haze.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
var layout := Control.new()
layout.name = "Layout"
layout.mouse_filter = Control.MOUSE_FILTER_IGNORE
add_child(layout)
# Design coordinates remain proportional on every window size.
resized.connect(func(): layout.scale = size / Vector2(1600, 900))
layout.scale = size / Vector2(1600, 900)
var logo := caption("BLOCKLINE", Vector2(60, 264), 48, Color("eeeae2"))
logo.reparent(layout, false)
var bars := caption("III", Vector2(348, 259), 58, ORANGE)
bars.reparent(layout, false)
var subtitle := caption("RELAY DISTRICT / LOCAL OPERATIONS", Vector2(62, 322), 12)
subtitle.reparent(layout, false)
var strip := ColorRect.new()
strip.color = Color("a9ada6")
strip.position = Vector2(1106, 57)
strip.size = Vector2(420, 24)
layout.add_child(strip)
var roster := caption("1 SPIELER / 8 MAX.", Vector2(1114, 58), 15, Color("181917"))
roster.reparent(layout, false)
var nameplate := caption((str(ui.game.nickname) if ui != null else "OPERATOR") + "\n\nLOKALES NETZWERK", Vector2(1130, 97), 17, ORANGE)
nameplate.reparent(layout, false)
if loading:
status = Label.new()
progress = ProgressBar.new()
var heading := caption("EINSATZ WIRD VORBEREITET", Vector2(62, 420), 22, ORANGE)
heading.reparent(layout, false)
layout.add_child(status)
status.position = Vector2(62, 465)
status.size = Vector2(480, 90)
status.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
status.add_theme_font_size_override("font_size", 17)
layout.add_child(progress)
progress.position = Vector2(62, 575)
progress.size = Vector2(430, 6)
progress.show_percentage = false
var fill := StyleBoxFlat.new()
fill.bg_color = ORANGE
progress.add_theme_stylebox_override("fill", fill)
var track := StyleBoxFlat.new()
track.bg_color = Color("34302a")
progress.add_theme_stylebox_override("background", track)
var count := caption("0 %", Vector2(62, 595), 14, ORANGE)
count.reparent(layout, false)
progress.value_changed.connect(func(value: float): count.text = "%02d %% / %d VON %d SCHRITTEN" % [int(progress.ratio * 100), int(value), int(progress.max_value)])
else:
var names := ["PLAY", "MULTIPLAYER", "LOADOUT", "OPERATOR", "SETTINGS", "QUIT"]
var actions: Array[Callable] = [ui.play_menu, ui.multiplayer_menu, ui.loadout_menu, ui.operator_menu, ui.settings_menu, func(): get_tree().quit()]
for index in names.size():
var button := Button.new()
button.text = names[index]
button.position = Vector2(62, 397 + index * 35)
button.size = Vector2(240, 32)
button.alignment = HORIZONTAL_ALIGNMENT_LEFT
button.add_theme_font_size_override("font_size", 20)
for state: String in ["normal", "hover", "pressed", "focus"]:
var style := StyleBoxFlat.new()
style.bg_color = Color(0,0,0,0) if state == "normal" else ORANGE
style.content_margin_left = 9
button.add_theme_stylebox_override(state, style)
button.add_theme_color_override("font_hover_color", Color.BLACK)
button.add_theme_color_override("font_focus_color", Color.BLACK)
button.pressed.connect(actions[index])
button.mouse_entered.connect(button.grab_focus)
layout.add_child(button)
if index == 0: button.grab_focus()
var footer := caption("RESSOURCEN LADEN / BITTE WARTEN" if loading else "ENTER AUSWÄHLEN / MAUS NAVIGATION", Vector2(62, 854), 13)
footer.reparent(layout, false)
var party := caption("LOKALER EINSATZ\nPARTY: OFFEN", Vector2(62, 736), 15)
party.reparent(layout, false)
var build := caption("BLOCKLINE / RELAY DISTRICT LAN • 28", Vector2(1070, 854), 12)
build.reparent(layout, false)
func _process(dt: float) -> void:
preview.render_target_update_mode = SubViewport.UPDATE_ALWAYS if is_visible_in_tree() else SubViewport.UPDATE_DISABLED
if not is_visible_in_tree(): return
elapsed += dt
if is_instance_valid(actor): actor.preview("pro_rifle__idle", elapsed)
queue_redraw()
func _draw() -> void:
draw_line(Vector2(0, size.y * 0.93), Vector2(size.x, size.y * 0.93), Color(0.6,0.5,0.35,0.28))