mirror of
https://github.com/ElHombreAlex/FTL-Faster-Than-Light-VR.git
synced 2026-10-06 01:00:06 +02:00
124 lines
4.7 KiB
GDScript
124 lines
4.7 KiB
GDScript
extends Node3D
|
|
|
|
const UI = preload("res://scripts/ftl_ui_theme.gd")
|
|
const WIDTH := 0.64
|
|
const HEIGHT := 0.10
|
|
const PIXELS := Vector2i(770,130)
|
|
const HULL_COLOR := Color("85ff79")
|
|
const FILL_RECT := Rect2(34, 0, 720, 130)
|
|
static var native_contour: Texture2D
|
|
var viewport: SubViewport
|
|
var canvas: Control
|
|
var plate: MeshInstance3D
|
|
var hull := 0
|
|
var hull_max := 0
|
|
var ship_label := "HOSTILE"
|
|
var signature := ""
|
|
|
|
|
|
func build() -> void:
|
|
viewport = SubViewport.new()
|
|
viewport.size = PIXELS
|
|
viewport.transparent_bg = true
|
|
viewport.render_target_update_mode = SubViewport.UPDATE_ONCE
|
|
add_child(viewport)
|
|
canvas = Control.new()
|
|
canvas.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
|
canvas.texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST
|
|
canvas.draw.connect(_draw)
|
|
viewport.add_child(canvas)
|
|
plate = MeshInstance3D.new()
|
|
var quad := QuadMesh.new()
|
|
quad.size = Vector2(WIDTH, HEIGHT)
|
|
plate.mesh = quad
|
|
var material := StandardMaterial3D.new()
|
|
material.albedo_texture = viewport.get_texture()
|
|
material.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA
|
|
material.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
|
|
material.texture_filter = BaseMaterial3D.TEXTURE_FILTER_NEAREST
|
|
material.cull_mode = BaseMaterial3D.CULL_DISABLED
|
|
plate.material_override = material
|
|
plate.cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_OFF
|
|
add_child(plate)
|
|
visible = false
|
|
|
|
|
|
func set_state(data: Dictionary) -> void:
|
|
hull = maxi(0, int(data.get("hull", 0)))
|
|
hull_max = maxi(0, int(data.get("hull_max", 0)))
|
|
ship_label = str(data.get("name", "HOSTILE")).to_upper()
|
|
if ship_label.is_empty():
|
|
ship_label = "HOSTILE"
|
|
visible = not data.is_empty() and hull_max > 0 and not bool(data.get("destroyed", false))
|
|
var next := "%d:%d:%s" % [hull, hull_max, ship_label]
|
|
if next == signature:
|
|
return
|
|
signature = next
|
|
canvas.queue_redraw()
|
|
viewport.render_target_update_mode = SubViewport.UPDATE_ONCE
|
|
|
|
|
|
func face_viewer(viewer: Vector3) -> void:
|
|
if visible and global_position.distance_squared_to(viewer) > 0.0001:
|
|
look_at(viewer, Vector3.UP, true)
|
|
|
|
|
|
func _draw() -> void:
|
|
var fraction := clampf(float(hull) / maxf(hull_max, 1), 0.0, 1.0)
|
|
var frame := UI.ASSETS.texture("img/statusUI/top_hull_red.png" if fraction <= .33 else "img/statusUI/top_hull.png")
|
|
var mask := _hull_contour()
|
|
var label := UI.ASSETS.texture("img/statusUI/top_hull_red_label.png" if fraction <= .33 else "img/statusUI/top_hull_label.png")
|
|
# Keep the owner's native stepped contour, but one pip means one hit point.
|
|
# The player mask's fixed thirty separators are replaced by hull_max cells.
|
|
if frame != null and mask != null and label != null:
|
|
var source_size := mask.get_size()
|
|
for i in range(hull_max):
|
|
var cell := hull_cell_rect(i)
|
|
var source := Rect2((cell.position - FILL_RECT.position) * source_size / FILL_RECT.size,
|
|
cell.size * source_size / FILL_RECT.size)
|
|
canvas.draw_texture_rect_region(mask, cell, source,
|
|
(HULL_COLOR if fraction > .33 else UI.RED) if i < hull else Color("253b32"))
|
|
canvas.draw_texture_rect(frame,Rect2(0,0,770,130),false)
|
|
canvas.draw_texture_rect(label,Rect2(18,0,104,56),false)
|
|
else:
|
|
# Missing owned art still leaves a readable small bar during setup.
|
|
var outline := PackedVector2Array([Vector2(16,80),Vector2(16,42),Vector2(255,42),Vector2(267,32),Vector2(496,32),Vector2(506,24),Vector2(755,24),Vector2(755,80),Vector2(16,80)])
|
|
canvas.draw_colored_polygon(outline,UI.DARK)
|
|
canvas.draw_polyline(outline,UI.EDGE,2)
|
|
for i in range(hull_max):
|
|
var cell := hull_cell_rect(i)
|
|
canvas.draw_rect(Rect2(cell.position.x,52,cell.size.x,22),
|
|
(HULL_COLOR if fraction > .33 else UI.RED) if i < hull else Color("253b32"))
|
|
UI.text(canvas,"HULL",Vector2(28,4),29,UI.DARK,"header")
|
|
UI.text(canvas,"%d / %d" % [hull,hull_max],Vector2(639,0),28,UI.INK)
|
|
|
|
|
|
func hull_cell_rect(index: int) -> Rect2:
|
|
var width := FILL_RECT.size.x / maxf(hull_max, 1)
|
|
var gap := minf(3.0, width * 0.18)
|
|
return Rect2(FILL_RECT.position + Vector2(index * width, 0), Vector2(width - gap, FILL_RECT.size.y))
|
|
|
|
|
|
static func _hull_contour() -> Texture2D:
|
|
if native_contour != null:
|
|
return native_contour
|
|
var mask := UI.ASSETS.texture("img/statusUI/top_hull_bar_mask.png")
|
|
if mask == null:
|
|
return null
|
|
var image := mask.get_image()
|
|
if image == null or image.is_empty():
|
|
return null
|
|
# Fill the mask's old gaps row by row, retaining its native alpha boundary.
|
|
# This is cached once and does not alter the shared owner-local texture.
|
|
for y in range(image.get_height()):
|
|
var left := image.get_width()
|
|
var right := -1
|
|
for x in range(image.get_width()):
|
|
if image.get_pixel(x, y).a > 0.5:
|
|
left = mini(left, x)
|
|
right = maxi(right, x)
|
|
for x in range(left, right + 1):
|
|
image.set_pixel(x, y, Color.WHITE)
|
|
native_contour = ImageTexture.create_from_image(image)
|
|
return native_contour
|