Checkpoint Player Menu visual revisions

This commit is contained in:
Alexander Sellite 2026-07-28 23:43:03 -04:00
parent bcffe2013d
commit 5af84eaf47
29 changed files with 3236 additions and 628 deletions

View file

@ -26,8 +26,8 @@ const DEFORMATION_Y_AMPLITUDE: float = 0.007
@export_range(0, PlayerHotbarType.SLOT_COUNT - 1, 1) var slot_index: int = 0
@export_group("Authored Layout")
@export var desktop_size: Vector2 = Vector2(80.0, 78.0)
@export var compact_size: Vector2 = Vector2(56.0, 54.0)
@export var desktop_size: Vector2 = Vector2(78.0, 78.0)
@export var compact_size: Vector2 = Vector2(54.0, 54.0)
@export var desktop_anchor: Vector2 = Vector2.ZERO
@export var compact_anchor: Vector2 = Vector2.ZERO
@export_group("Motion")
@ -204,29 +204,31 @@ func _apply_style() -> void:
return
var normal_fill: Color = profile.normal_fill
normal_fill.a = 1.0
var normal_border: Color = profile.normal_border
var normal_border_width: int = profile.normal_border_width
var selected_fill: Color = normal_fill
if _selected:
normal_border = profile.pressed_border
normal_border_width = profile.emphasized_border_width
selected_fill = normal_fill.lightened(0.12)
add_theme_stylebox_override(
"normal",
_make_style(normal_fill, normal_border, normal_border_width)
_make_style(
selected_fill,
5 if _selected else 2,
0.38 if _selected else 0.20,
)
)
add_theme_stylebox_override(
"hover",
_make_style(
normal_fill,
profile.hover_border,
profile.emphasized_border_width
selected_fill.lightened(0.055),
5 if _selected else 3,
0.40 if _selected else 0.29,
)
)
add_theme_stylebox_override(
"pressed",
_make_style(
normal_fill,
profile.pressed_border,
profile.emphasized_border_width
selected_fill.lightened(0.085),
6,
0.44,
)
)
add_theme_stylebox_override(
@ -237,8 +239,8 @@ func _apply_style() -> void:
"disabled",
_make_style(
normal_fill,
profile.disabled_border,
profile.normal_border_width
1,
0.12,
)
)
add_theme_color_override("font_color", profile.text_color)
@ -249,21 +251,20 @@ func _apply_style() -> void:
func _make_style(
fill_color: Color,
border_color: Color,
border_width: int,
shadow_size: int,
shadow_alpha: float,
) -> StyleBoxFlat:
var style := StyleBoxFlat.new()
style.bg_color = fill_color
style.border_color = border_color
style.border_width_left = border_width
style.border_width_top = border_width
style.border_width_right = border_width
style.border_width_bottom = border_width
style.set_border_width_all(0)
var radius: int = ceili(maxf(_presented_size.x, _presented_size.y) * 0.5)
style.corner_radius_top_left = radius
style.corner_radius_top_right = radius
style.corner_radius_bottom_right = radius
style.corner_radius_bottom_left = radius
style.shadow_color = Color(0.015, 0.06, 0.09, shadow_alpha)
style.shadow_size = shadow_size
style.shadow_offset = Vector2(0.0, 2.0)
return style

View file

@ -5,7 +5,7 @@
[ext_resource type="Theme" path="res://ui/game_theme.tres" id="3_theme"]
[node name="BubbleHotbarSlot" type="Button"]
custom_minimum_size = Vector2(80, 78)
custom_minimum_size = Vector2(78, 78)
focus_mode = 0
mouse_default_cursor_shape = 2
theme = ExtResource("3_theme")

View file

@ -0,0 +1,131 @@
class_name BagItemSprite
extends ItemDragSource
signal drag_started
signal drag_finished
@onready var _visual_root: Control = %VisualRoot
@onready var _item_texture: TextureRect = %ItemTexture
@onready var _quantity_badge: PanelContainer = %QuantityBadge
@onready var _quantity_label: Label = %QuantityLabel
@onready var _compatibility_marker: Label = %CompatibilityMarker
var _motion_phase: float = 0.0
var _depth_scale: float = 1.0
var _selected: bool = false
var _hovered: bool = false
var _dragging: bool = false
func _ready() -> void:
mouse_entered.connect(_set_hovered.bind(true))
mouse_exited.connect(_set_hovered.bind(false))
focus_entered.connect(_refresh_style)
focus_exited.connect(_refresh_style)
resized.connect(_update_visual_pivot)
_update_visual_pivot()
_apply_quantity_style()
_refresh_style()
func configure_item(
new_item_id: StringName,
new_item_name: String,
new_icon: Texture2D,
quantity: int,
hotbar_compatible: bool,
phase: float,
depth_scale: float,
) -> void:
setup(new_item_id, new_item_name, new_icon)
_item_texture.texture = new_icon
_quantity_label.text = "×%d" % quantity
_quantity_badge.visible = quantity > 1
_compatibility_marker.visible = not hotbar_compatible
_motion_phase = phase
_depth_scale = depth_scale
func set_selected(selected: bool) -> void:
_selected = selected
_refresh_style()
func advance_presentation(elapsed: float, motion_enabled: bool) -> void:
if not motion_enabled or _dragging:
return
var bob: float = sin(elapsed * TAU / 7.4 + _motion_phase) * 0.9
var tilt: float = sin(
elapsed * TAU / 10.2 + _motion_phase * 1.29
) * 0.014
_visual_root.position = Vector2(0.0, bob)
_visual_root.rotation = tilt
var emphasis: float = 1.04 if _hovered or has_focus() else 1.0
_visual_root.scale = Vector2.ONE * _depth_scale * emphasis
func _get_drag_data(at_position: Vector2) -> Variant:
var payload: Variant = super(at_position)
if payload != null:
_dragging = true
drag_started.emit()
return payload
func _notification(what: int) -> void:
if what == NOTIFICATION_DRAG_END and _dragging:
_dragging = false
drag_finished.emit()
func _has_point(point: Vector2) -> bool:
var radius: Vector2 = size * Vector2(0.46, 0.42)
if radius.x <= 0.0 or radius.y <= 0.0:
return false
var normalized: Vector2 = (point - size * 0.5) / radius
return normalized.length_squared() <= 1.0
func _set_hovered(hovered: bool) -> void:
_hovered = hovered
_refresh_style()
func _update_visual_pivot() -> void:
_visual_root.pivot_offset = size * 0.5
func _refresh_style() -> void:
var style := StyleBoxFlat.new()
style.bg_color = Color(0.95, 0.9, 0.75, 0.12) if _selected else Color.TRANSPARENT
style.border_color = Color.TRANSPARENT
var width: int = 0
if _selected:
style.border_color = Color(0.28, 0.19, 0.1, 1.0)
width = 4
if has_focus():
style.border_color = Color(0.035, 0.145, 0.22, 1.0)
width = 4
elif _hovered:
style.border_color = Color(0.48, 0.35, 0.2, 0.9)
width = 2
style.set_border_width_all(width)
style.set_corner_radius_all(64)
for state: StringName in [
&"normal",
&"hover",
&"focus",
&"pressed",
]:
add_theme_stylebox_override(state, style)
func _apply_quantity_style() -> void:
var style := StyleBoxFlat.new()
style.bg_color = Color(0.94, 0.86, 0.64, 1.0)
style.border_color = Color(0.31, 0.22, 0.12, 1.0)
style.set_border_width_all(2)
style.set_corner_radius_all(18)
style.content_margin_left = 5.0
style.content_margin_right = 5.0
_quantity_badge.add_theme_stylebox_override("panel", style)

View file

@ -0,0 +1 @@
uid://dgbagitemsprite2026

View file

@ -0,0 +1,83 @@
[gd_scene load_steps=2 format=3]
[ext_resource type="Script" path="res://ui/components/bubble_menu/bag_item_sprite.gd" id="1_script"]
[node name="BagItemSprite" type="Button"]
custom_minimum_size = Vector2(118, 86)
focus_mode = 1
mouse_default_cursor_shape = 2
script = ExtResource("1_script")
[node name="VisualRoot" type="Control" parent="."]
unique_name_in_owner = true
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
mouse_filter = 2
[node name="ItemTexture" type="TextureRect" parent="VisualRoot"]
unique_name_in_owner = true
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
offset_left = 10.0
offset_top = 8.0
offset_right = -10.0
offset_bottom = -8.0
grow_horizontal = 2
grow_vertical = 2
mouse_filter = 2
texture_filter = 1
expand_mode = 1
stretch_mode = 5
[node name="QuantityBadge" type="PanelContainer" parent="VisualRoot"]
unique_name_in_owner = true
visible = false
layout_mode = 1
anchors_preset = 3
anchor_left = 1.0
anchor_top = 1.0
anchor_right = 1.0
anchor_bottom = 1.0
offset_left = -42.0
offset_top = -28.0
offset_right = -2.0
offset_bottom = -2.0
grow_horizontal = 0
grow_vertical = 0
mouse_filter = 2
[node name="QuantityLabel" type="Label" parent="VisualRoot/QuantityBadge"]
unique_name_in_owner = true
layout_mode = 2
mouse_filter = 2
theme_override_colors/font_color = Color(0.17, 0.105, 0.05, 1)
theme_override_font_sizes/font_size = 15
text = "×2"
horizontal_alignment = 1
vertical_alignment = 1
[node name="CompatibilityMarker" type="Label" parent="VisualRoot"]
unique_name_in_owner = true
visible = false
layout_mode = 1
anchors_preset = 1
anchor_left = 1.0
anchor_right = 1.0
offset_left = -28.0
offset_top = 0.0
offset_right = -2.0
offset_bottom = 24.0
grow_horizontal = 0
mouse_filter = 2
theme_override_colors/font_color = Color(0.31, 0.22, 0.12, 1)
theme_override_colors/font_outline_color = Color(0.96, 0.93, 0.82, 1)
theme_override_constants/outline_size = 2
theme_override_font_sizes/font_size = 17
text = "×"
horizontal_alignment = 1

View file

@ -1,125 +0,0 @@
class_name BubbleInventoryCell
extends Button
@export var profile: BubbleMenuProfile
@onready var _icon: TextureRect = %Icon
@onready var _primary_label: Label = %PrimaryLabel
@onready var _secondary_label: Label = %SecondaryLabel
@onready var _favorite_marker: Label = %FavoriteMarker
@onready var _selected_marker: Label = %SelectedMarker
var _selected: bool = false
var _focused_item: bool = false
var _compact: bool = false
var _icon_texture: Texture2D
var _primary_text: String = ""
var _secondary_text: String = ""
var _favorite: bool = false
func _ready() -> void:
focus_entered.connect(_refresh_style)
focus_exited.connect(_refresh_style)
_apply_compact_layout()
_apply_content()
_refresh_style()
func configure(
icon_texture: Texture2D,
primary_text: String,
secondary_text: String,
) -> void:
_icon_texture = icon_texture
_primary_text = primary_text
_secondary_text = secondary_text
if is_node_ready():
_apply_content()
func set_item_state(
selected: bool,
focused_item: bool,
favorite: bool,
) -> void:
_selected = selected
_focused_item = focused_item
_favorite = favorite
if is_node_ready():
_apply_content()
_refresh_style()
func set_compact(compact: bool) -> void:
_compact = compact
if not is_node_ready():
custom_minimum_size = (
Vector2(104.0, 98.0)
if compact
else Vector2(144.0, 136.0)
)
return
_apply_compact_layout()
func _apply_compact_layout() -> void:
custom_minimum_size = (
Vector2(104.0, 98.0)
if _compact
else Vector2(144.0, 136.0)
)
_icon.custom_minimum_size = (
Vector2(72.0, 44.0)
if _compact
else Vector2(104.0, 68.0)
)
_primary_label.add_theme_font_size_override(
"font_size",
15 if _compact else 18,
)
_secondary_label.add_theme_font_size_override(
"font_size",
13 if _compact else 15,
)
func _apply_content() -> void:
_icon.texture = _icon_texture
_primary_label.text = _primary_text
_secondary_label.text = _secondary_text
_selected_marker.visible = _selected
_favorite_marker.visible = _favorite
func _has_point(point: Vector2) -> bool:
var radius: Vector2 = size * 0.5
if radius.x <= 0.0 or radius.y <= 0.0:
return false
var normalized: Vector2 = (point - radius) / radius
return normalized.length_squared() <= 1.0
func _refresh_style() -> void:
if profile == null:
return
var normal_style: StyleBoxFlat = profile.make_normal_style()
var border_width: int = (
profile.emphasized_border_width
if _selected or _focused_item or has_focus()
else profile.normal_border_width
)
normal_style.border_width_left = border_width
normal_style.border_width_top = border_width
normal_style.border_width_right = border_width
normal_style.border_width_bottom = border_width
if _selected:
normal_style.bg_color = profile.pressed_fill
if _focused_item:
normal_style.border_color = profile.text_color
add_theme_stylebox_override("normal", normal_style)
add_theme_stylebox_override("hover", profile.make_hover_style())
add_theme_stylebox_override("focus", normal_style)
add_theme_stylebox_override("pressed", profile.make_pressed_style())
add_theme_stylebox_override("disabled", profile.make_disabled_style())
add_theme_color_override("font_color", profile.text_color)

View file

@ -1 +0,0 @@
uid://bubbleinventorycell

View file

@ -1,78 +0,0 @@
[gd_scene load_steps=3 format=3]
[ext_resource type="Script" path="res://ui/components/bubble_menu/bubble_inventory_cell.gd" id="1_cell"]
[ext_resource type="Resource" path="res://ui/components/bubble_menu/bubble_menu_profile.tres" id="2_profile"]
[node name="BubbleInventoryCell" type="Button"]
custom_minimum_size = Vector2(144, 136)
toggle_mode = true
script = ExtResource("1_cell")
profile = ExtResource("2_profile")
[node name="Content" type="VBoxContainer" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
offset_left = 17.0
offset_top = 14.0
offset_right = -17.0
offset_bottom = -14.0
grow_horizontal = 2
grow_vertical = 2
mouse_filter = 2
theme_override_constants/separation = 2
[node name="Icon" type="TextureRect" parent="Content"]
unique_name_in_owner = true
custom_minimum_size = Vector2(104, 68)
layout_mode = 2
size_flags_vertical = 3
mouse_filter = 2
texture_filter = 1
expand_mode = 1
stretch_mode = 5
[node name="PrimaryLabel" type="Label" parent="Content"]
unique_name_in_owner = true
layout_mode = 2
mouse_filter = 2
theme_override_font_sizes/font_size = 18
horizontal_alignment = 1
text_overrun_behavior = 3
[node name="SecondaryLabel" type="Label" parent="Content"]
unique_name_in_owner = true
layout_mode = 2
mouse_filter = 2
theme_override_colors/font_color = Color(0.16, 0.25, 0.29, 0.78)
theme_override_font_sizes/font_size = 15
horizontal_alignment = 1
[node name="FavoriteMarker" type="Label" parent="."]
unique_name_in_owner = true
visible = false
layout_mode = 0
offset_left = 102.0
offset_top = 12.0
offset_right = 132.0
offset_bottom = 42.0
mouse_filter = 2
theme_override_colors/font_color = Color(1, 0.82, 0.4, 1)
theme_override_font_sizes/font_size = 23
text = "★"
horizontal_alignment = 1
[node name="SelectedMarker" type="Label" parent="."]
unique_name_in_owner = true
visible = false
layout_mode = 0
offset_left = 14.0
offset_top = 10.0
offset_right = 42.0
offset_bottom = 38.0
mouse_filter = 2
theme_override_colors/font_color = Color(0.035, 0.145, 0.22, 1)
theme_override_font_sizes/font_size = 22
text = "✓"
horizontal_alignment = 1

View file

@ -4,7 +4,7 @@
[ext_resource type="Resource" path="res://ui/components/bubble_menu/bubble_menu_profile.tres" id="2_profile"]
[node name="BubbleStatusBubble" type="PanelContainer"]
custom_minimum_size = Vector2(128, 88)
custom_minimum_size = Vector2(112, 62)
mouse_filter = 2
script = ExtResource("1_status")
profile = ExtResource("2_profile")
@ -19,7 +19,7 @@ alignment = 1
unique_name_in_owner = true
layout_mode = 2
mouse_filter = 2
theme_override_font_sizes/font_size = 15
theme_override_font_sizes/font_size = 13
text = "status"
horizontal_alignment = 1
@ -27,6 +27,6 @@ horizontal_alignment = 1
unique_name_in_owner = true
layout_mode = 2
mouse_filter = 2
theme_override_font_sizes/font_size = 21
theme_override_font_sizes/font_size = 18
text = "0"
horizontal_alignment = 1

View file

@ -0,0 +1,140 @@
class_name CoolerFishSprite
extends Button
@onready var _visual_root: Control = %VisualRoot
@onready var _fish_shadow: TextureRect = %FishShadow
@onready var _fish_texture: TextureRect = %FishTexture
@onready var _favorite_marker: Label = %FavoriteMarker
var catch_id: StringName
var _neutral_position := Vector2.ZERO
var _target_position := Vector2.ZERO
var _motion_phase: float = 0.0
var _depth_scale: float = 1.0
var _batch_selected: bool = false
var _focused_catch: bool = false
var _hovered: bool = false
var _rarity_color := Color.WHITE
func _ready() -> void:
resized.connect(_update_visual_pivot)
focus_entered.connect(_refresh_style)
focus_exited.connect(_refresh_style)
mouse_entered.connect(func() -> void:
_hovered = true
_refresh_style()
)
mouse_exited.connect(func() -> void:
_hovered = false
_refresh_style()
)
_update_visual_pivot()
_refresh_style()
func configure(
identity: StringName,
texture: Texture2D,
phase: float,
depth_scale: float,
rarity_color: Color,
) -> void:
catch_id = identity
_fish_texture.texture = texture
_fish_shadow.texture = texture
_motion_phase = phase
_depth_scale = depth_scale
_rarity_color = rarity_color
_refresh_style()
func set_target_position(target: Vector2, immediate: bool = false) -> void:
_target_position = target
if immediate:
_neutral_position = target
position = _neutral_position
func set_item_state(
batch_selected: bool,
focused_catch: bool,
favorite: bool,
) -> void:
_batch_selected = batch_selected
_focused_catch = focused_catch
_favorite_marker.visible = favorite
_refresh_style()
func advance_presentation(delta: float, elapsed: float) -> void:
var response: float = 1.0 - exp(-9.0 * delta)
_neutral_position = _neutral_position.lerp(_target_position, response)
position = _neutral_position
var bob: float = sin(elapsed * TAU / 7.2 + _motion_phase) * 1.1
var tilt: float = sin(elapsed * TAU / 9.0 + _motion_phase * 1.31) * 0.018
var interaction_lift: float = 0.0
if _batch_selected:
interaction_lift += 3.0
if _focused_catch or has_focus():
interaction_lift += 1.5
elif _hovered:
interaction_lift += 0.8
_visual_root.position = Vector2(0.0, bob - interaction_lift)
_visual_root.rotation = tilt
var emphasis: float = 1.0
if _batch_selected:
emphasis += 0.085
if _focused_catch or has_focus():
emphasis += 0.035
elif _hovered:
emphasis += 0.045
_visual_root.scale = Vector2.ONE * _depth_scale * emphasis
func _has_point(point: Vector2) -> bool:
var radius: float = minf(size.x, size.y) * 0.48
if radius <= 0.0:
return false
return (point - size * 0.5).length_squared() <= radius * radius
func _update_visual_pivot() -> void:
_visual_root.pivot_offset = size * 0.5
func _refresh_style() -> void:
var normal := _make_rarity_style(_rarity_color, 2, 0.25)
var hover := _make_rarity_style(_rarity_color.lightened(0.08), 4, 0.34)
var selected_fill: Color = (
_rarity_color.lightened(0.12)
if _batch_selected
else _rarity_color
)
var selected := _make_rarity_style(
selected_fill,
6 if _batch_selected else 4,
0.46 if _batch_selected else 0.34,
)
add_theme_stylebox_override(
"normal",
selected if _batch_selected or _focused_catch else normal,
)
add_theme_stylebox_override("hover", selected if _batch_selected else hover)
add_theme_stylebox_override("focus", selected)
add_theme_stylebox_override("pressed", selected)
func _make_rarity_style(
fill: Color,
shadow_size: int,
shadow_alpha: float,
) -> StyleBoxFlat:
var style := StyleBoxFlat.new()
style.bg_color = fill
style.set_border_width_all(0)
style.set_corner_radius_all(128)
style.shadow_color = Color(0.01, 0.045, 0.06, shadow_alpha)
style.shadow_size = shadow_size
style.shadow_offset = Vector2(0.0, 2.0)
return style

View file

@ -0,0 +1 @@
uid://dscoolerfishsprite

View file

@ -0,0 +1,75 @@
[gd_scene load_steps=2 format=3]
[ext_resource type="Script" path="res://ui/components/bubble_menu/cooler_fish_sprite.gd" id="1_script"]
[node name="CoolerFishSprite" type="Button"]
custom_minimum_size = Vector2(72, 72)
focus_mode = 1
mouse_default_cursor_shape = 2
script = ExtResource("1_script")
[node name="VisualRoot" type="Control" parent="."]
unique_name_in_owner = true
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
mouse_filter = 2
pivot_offset = Vector2(36, 36)
[node name="FishShadow" type="TextureRect" parent="VisualRoot"]
unique_name_in_owner = true
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
offset_left = 10.0
offset_top = 11.0
offset_right = -4.0
offset_bottom = -3.0
grow_horizontal = 2
grow_vertical = 2
mouse_filter = 2
modulate = Color(0.015, 0.055, 0.07, 0.32)
texture_filter = 1
expand_mode = 1
stretch_mode = 5
[node name="FishTexture" type="TextureRect" parent="VisualRoot"]
unique_name_in_owner = true
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
offset_left = 7.0
offset_top = 7.0
offset_right = -7.0
offset_bottom = -7.0
grow_horizontal = 2
grow_vertical = 2
mouse_filter = 2
texture_filter = 1
expand_mode = 1
stretch_mode = 5
[node name="FavoriteMarker" type="Label" parent="VisualRoot"]
unique_name_in_owner = true
visible = false
layout_mode = 1
anchors_preset = 1
anchor_left = 1.0
anchor_right = 1.0
offset_left = -22.0
offset_top = 0.0
offset_right = 0.0
offset_bottom = 22.0
grow_horizontal = 0
mouse_filter = 2
theme_override_colors/font_color = Color(0.92, 0.68, 0.16, 1)
theme_override_colors/font_outline_color = Color(0.035, 0.145, 0.22, 1)
theme_override_constants/outline_size = 2
theme_override_font_sizes/font_size = 16
text = "★"
horizontal_alignment = 1

View file

@ -0,0 +1,40 @@
shader_type canvas_item;
render_mode unshaded;
uniform vec4 water_top : source_color = vec4(0.055, 0.38, 0.50, 1.0);
uniform vec4 water_bottom : source_color = vec4(0.018, 0.16, 0.25, 1.0);
uniform vec4 caustic_color : source_color = vec4(0.66, 0.91, 0.95, 1.0);
uniform float caustic_opacity : hint_range(0.0, 0.2) = 0.055;
uniform float caustic_speed : hint_range(0.0, 0.2) = 0.045;
uniform float bubble_opacity : hint_range(0.0, 0.25) = 0.11;
float hash(float value) {
return fract(sin(value * 91.713) * 43758.5453);
}
void fragment() {
vec2 uv = UV;
vec3 base = mix(water_top.rgb, water_bottom.rgb, smoothstep(0.0, 1.0, uv.y));
float slow_time = TIME * caustic_speed;
float broad_wave = sin((uv.x * 8.0 + uv.y * 5.0 + slow_time) * 6.28318);
float crossing_wave = sin((uv.x * 5.5 - uv.y * 7.0 - slow_time * 0.73) * 6.28318);
float caustic = smoothstep(1.46, 1.88, broad_wave + crossing_wave);
base += caustic_color.rgb * caustic * caustic_opacity;
float sheen = (1.0 - smoothstep(0.0, 0.12, uv.y)) * 0.11;
base += caustic_color.rgb * sheen;
float bubbles = 0.0;
for (int index = 0; index < 8; index++) {
float key = float(index) + 1.0;
float x = 0.08 + hash(key * 2.13) * 0.84;
float phase = hash(key * 4.71);
float y = 1.08 - mod(slow_time * (0.42 + hash(key) * 0.34) + phase, 1.18);
float radius = 0.005 + hash(key * 8.23) * 0.008;
vec2 delta = uv - vec2(x, y);
delta.x *= 0.62;
float distance_to_edge = abs(length(delta) - radius);
bubbles += 1.0 - smoothstep(0.0015, 0.004, distance_to_edge);
}
base += caustic_color.rgb * min(bubbles, 1.0) * bubble_opacity;
COLOR = vec4(base, 1.0);
}

View file

@ -0,0 +1 @@
uid://dejhqrp2nij1

View file

@ -0,0 +1,103 @@
class_name LogbookEntry
extends PanelContainer
var _discovered: bool = false
func _ready() -> void:
mouse_filter = Control.MOUSE_FILTER_IGNORE
_apply_paper_style(_discovered)
func configure(
artwork: Texture2D,
species_name: String,
rarity_name: String,
owned_count: int,
discovered: bool,
) -> void:
_discovered = discovered
var artwork_control := get_node(
^"Margin/Content/Artwork"
) as TextureRect
var name_control := get_node(
^"Margin/Content/Text/NameLabel"
) as Label
var rarity_control := get_node(
^"Margin/Content/Text/RarityLabel"
) as Label
var owned_control := get_node(
^"Margin/Content/Text/OwnedLabel"
) as Label
artwork_control.texture = artwork
artwork_control.modulate = (
Color.WHITE
if discovered
else Color(0.20, 0.17, 0.13, 0.48)
)
name_control.text = species_name if discovered else "???"
rarity_control.text = rarity_name if discovered else "undiscovered"
owned_control.text = (
"owned: %d" % owned_count if discovered else "not recorded"
)
owned_control.visible = true
_apply_paper_style(discovered)
func apply_compact_layout(compact: bool) -> void:
var artwork_control := get_node(
^"Margin/Content/Artwork"
) as TextureRect
var name_control := get_node(
^"Margin/Content/Text/NameLabel"
) as Label
var rarity_control := get_node(
^"Margin/Content/Text/RarityLabel"
) as Label
var owned_control := get_node(
^"Margin/Content/Text/OwnedLabel"
) as Label
custom_minimum_size = (
Vector2(236.0, 108.0) if compact else Vector2(214.0, 150.0)
)
artwork_control.custom_minimum_size = (
Vector2(92.0, 54.0) if compact else Vector2(128.0, 76.0)
)
name_control.add_theme_font_size_override(
"font_size",
16 if compact else 18,
)
rarity_control.add_theme_font_size_override(
"font_size",
11 if compact else 13,
)
owned_control.add_theme_font_size_override(
"font_size",
11 if compact else 13,
)
func _apply_paper_style(discovered: bool) -> void:
if not is_node_ready():
return
var style := StyleBoxFlat.new()
style.bg_color = (
Color(0.965, 0.925, 0.80, 0.78)
if discovered
else Color(0.89, 0.84, 0.72, 0.58)
)
style.border_color = (
Color(0.50, 0.39, 0.25, 0.62)
if discovered
else Color(0.39, 0.34, 0.27, 0.42)
)
style.border_width_bottom = 2
style.corner_radius_top_left = 18
style.corner_radius_top_right = 12
style.corner_radius_bottom_right = 16
style.corner_radius_bottom_left = 10
style.content_margin_left = 8.0
style.content_margin_top = 6.0
style.content_margin_right = 8.0
style.content_margin_bottom = 6.0
add_theme_stylebox_override("panel", style)

View file

@ -0,0 +1 @@
uid://dclogbookentry2026

View file

@ -0,0 +1,66 @@
[gd_scene load_steps=2 format=3]
[ext_resource type="Script" path="res://ui/components/bubble_menu/logbook_entry.gd" id="1_script"]
[node name="LogbookEntry" type="PanelContainer"]
custom_minimum_size = Vector2(214, 150)
mouse_filter = 2
script = ExtResource("1_script")
[node name="Margin" type="MarginContainer" parent="."]
layout_mode = 2
mouse_filter = 2
theme_override_constants/margin_left = 5
theme_override_constants/margin_top = 4
theme_override_constants/margin_right = 5
theme_override_constants/margin_bottom = 4
[node name="Content" type="HBoxContainer" parent="Margin"]
layout_mode = 2
mouse_filter = 2
theme_override_constants/separation = 7
[node name="Artwork" type="TextureRect" parent="Margin/Content"]
unique_name_in_owner = true
custom_minimum_size = Vector2(128, 76)
layout_mode = 2
size_flags_horizontal = 3
mouse_filter = 2
texture_filter = 1
expand_mode = 1
stretch_mode = 5
[node name="Text" type="VBoxContainer" parent="Margin/Content"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 4
mouse_filter = 2
theme_override_constants/separation = 2
[node name="NameLabel" type="Label" parent="Margin/Content/Text"]
unique_name_in_owner = true
layout_mode = 2
mouse_filter = 2
theme_override_colors/font_color = Color(0.20, 0.145, 0.085, 1)
theme_override_font_sizes/font_size = 18
text = "species"
horizontal_alignment = 1
autowrap_mode = 2
[node name="RarityLabel" type="Label" parent="Margin/Content/Text"]
unique_name_in_owner = true
layout_mode = 2
mouse_filter = 2
theme_override_colors/font_color = Color(0.34, 0.25, 0.15, 1)
theme_override_font_sizes/font_size = 13
text = "common"
horizontal_alignment = 1
[node name="OwnedLabel" type="Label" parent="Margin/Content/Text"]
unique_name_in_owner = true
layout_mode = 2
mouse_filter = 2
theme_override_colors/font_color = Color(0.34, 0.25, 0.15, 1)
theme_override_font_sizes/font_size = 13
text = "owned: 0"
horizontal_alignment = 1

View file

@ -0,0 +1,82 @@
class_name NotepadInkAction
extends Button
@export var ink_color := Color(0.19, 0.16, 0.12, 1.0)
@export var disabled_ink_color := Color(0.31, 0.28, 0.23, 0.46)
@export var persistent_mark: bool = false:
set(value):
persistent_mark = value
_refresh_ink()
@onready var _ink_outline: NotepadInkOutline = %InkOutline
var _hovered: bool = false
var _focused: bool = false
var _pressed: bool = false
func _ready() -> void:
mouse_entered.connect(_set_hovered.bind(true))
mouse_exited.connect(_set_hovered.bind(false))
focus_entered.connect(_set_focused.bind(true))
focus_exited.connect(_set_focused.bind(false))
button_down.connect(_set_pressed.bind(true))
button_up.connect(_set_pressed.bind(false))
_apply_paper_style()
_refresh_ink()
func refresh_ink_state() -> void:
_apply_text_color()
_refresh_ink()
func _set_hovered(value: bool) -> void:
_hovered = value
_refresh_ink()
func _set_focused(value: bool) -> void:
_focused = value
_refresh_ink()
func _set_pressed(value: bool) -> void:
_pressed = value
_refresh_ink()
func _refresh_ink() -> void:
if not is_node_ready():
return
var strength: float = 0.0
if not disabled:
if persistent_mark:
strength = 0.78
if _hovered or _focused:
strength = maxf(strength, 0.92)
if _pressed:
strength = 1.0
_ink_outline.set_mark_strength(strength)
func _apply_paper_style() -> void:
var empty := StyleBoxEmpty.new()
for state: StringName in [
&"normal",
&"hover",
&"pressed",
&"focus",
&"disabled",
]:
add_theme_stylebox_override(state, empty)
_apply_text_color()
func _apply_text_color() -> void:
var color: Color = disabled_ink_color if disabled else ink_color
add_theme_color_override("font_color", color)
add_theme_color_override("font_hover_color", color.darkened(0.08))
add_theme_color_override("font_focus_color", color.darkened(0.08))
add_theme_color_override("font_pressed_color", color.darkened(0.16))
add_theme_color_override("font_disabled_color", disabled_ink_color)

View file

@ -0,0 +1 @@
uid://b42bnpyhxn35k

View file

@ -0,0 +1,23 @@
[gd_scene load_steps=3 format=3]
[ext_resource type="Script" path="res://ui/components/bubble_menu/notepad_ink_action.gd" id="1_action"]
[ext_resource type="Script" path="res://ui/components/bubble_menu/notepad_ink_outline.gd" id="2_outline"]
[node name="NotepadInkAction" type="Button"]
custom_minimum_size = Vector2(104, 46)
focus_mode = 1
mouse_default_cursor_shape = 2
flat = true
script = ExtResource("1_action")
[node name="InkOutline" type="Control" parent="."]
unique_name_in_owner = true
visible = false
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
mouse_filter = 2
script = ExtResource("2_outline")

View file

@ -0,0 +1,114 @@
class_name NotepadInkChoice
extends OptionButton
@export var ink_color := Color(0.19, 0.16, 0.12, 1.0)
@onready var _ink_outline: NotepadInkOutline = %InkOutline
var _hovered: bool = false
var _focused: bool = false
func _ready() -> void:
mouse_entered.connect(_set_hovered.bind(true))
mouse_exited.connect(_set_hovered.bind(false))
focus_entered.connect(_set_focused.bind(true))
focus_exited.connect(_set_focused.bind(false))
_apply_paper_style()
_style_popup()
queue_redraw()
func refresh_ink_state() -> void:
_refresh_ink()
func _draw() -> void:
var chevron_x: float = size.x - 13.0
var chevron_y: float = size.y * 0.5 - 1.0
var chevron := PackedVector2Array([
Vector2(chevron_x - 4.0, chevron_y - 2.0),
Vector2(chevron_x, chevron_y + 2.0),
Vector2(chevron_x + 4.0, chevron_y - 2.5),
])
draw_polyline(chevron, ink_color, 1.8, true)
var underline_y: float = size.y - 5.0
var underline := PackedVector2Array([
Vector2(7.0, underline_y),
Vector2(size.x * 0.34, underline_y + 0.7),
Vector2(size.x * 0.68, underline_y - 0.5),
Vector2(size.x - 8.0, underline_y + 0.2),
])
var underline_color: Color = ink_color
underline_color.a = 0.48
draw_polyline(underline, underline_color, 1.1, true)
func _set_hovered(value: bool) -> void:
_hovered = value
_refresh_ink()
func _set_focused(value: bool) -> void:
_focused = value
_refresh_ink()
func _refresh_ink() -> void:
if is_node_ready():
_ink_outline.set_mark_strength(
0.88 if (_hovered or _focused) and not disabled else 0.0
)
func _apply_paper_style() -> void:
var empty := StyleBoxEmpty.new()
for state: StringName in [
&"normal",
&"hover",
&"pressed",
&"focus",
&"disabled",
]:
add_theme_stylebox_override(state, empty)
var empty_arrow := ImageTexture.new()
add_theme_icon_override("arrow", empty_arrow)
add_theme_color_override("font_color", ink_color)
add_theme_color_override("font_hover_color", ink_color.darkened(0.08))
add_theme_color_override("font_focus_color", ink_color.darkened(0.08))
add_theme_color_override("font_pressed_color", ink_color.darkened(0.14))
add_theme_color_override("font_disabled_color", Color(ink_color, 0.42))
func _style_popup() -> void:
var popup: PopupMenu = get_popup()
var paper := StyleBoxFlat.new()
paper.bg_color = Color(0.93, 0.885, 0.73, 1.0)
paper.border_color = Color(0.22, 0.19, 0.15, 1.0)
paper.set_border_width_all(2)
paper.set_corner_radius_all(5)
var hover_paper := paper.duplicate() as StyleBoxFlat
hover_paper.bg_color = Color(0.82, 0.775, 0.63, 1.0)
hover_paper.border_color = Color(0.30, 0.26, 0.20, 0.62)
hover_paper.set_border_width_all(1)
popup.add_theme_stylebox_override("panel", paper)
popup.add_theme_stylebox_override("hover", hover_paper)
popup.add_theme_stylebox_override("separator", StyleBoxEmpty.new())
popup.add_theme_color_override("font_color", ink_color)
popup.add_theme_color_override("font_hover_color", ink_color.darkened(0.08))
popup.add_theme_color_override(
"font_separator_color",
Color(ink_color, 0.56),
)
var empty_mark := ImageTexture.new()
for icon_name: StringName in [
&"checked",
&"unchecked",
&"radio_checked",
&"radio_unchecked",
&"checked_disabled",
&"unchecked_disabled",
&"radio_checked_disabled",
&"radio_unchecked_disabled",
]:
popup.add_theme_icon_override(icon_name, empty_mark)

View file

@ -0,0 +1 @@
uid://h754d8qatlse

View file

@ -0,0 +1,24 @@
[gd_scene load_steps=3 format=3]
[ext_resource type="Script" path="res://ui/components/bubble_menu/notepad_ink_choice.gd" id="1_choice"]
[ext_resource type="Script" path="res://ui/components/bubble_menu/notepad_ink_outline.gd" id="2_outline"]
[node name="NotepadInkChoice" type="OptionButton"]
custom_minimum_size = Vector2(124, 38)
focus_mode = 1
mouse_default_cursor_shape = 2
clip_text = true
fit_to_longest_item = false
script = ExtResource("1_choice")
[node name="InkOutline" type="Control" parent="."]
unique_name_in_owner = true
visible = false
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
mouse_filter = 2
script = ExtResource("2_outline")

View file

@ -0,0 +1,64 @@
class_name NotepadInkOutline
extends Control
@export var ink_color := Color(0.20, 0.17, 0.13, 0.9)
@export_range(0.5, 6.0, 0.1) var stroke_width: float = 2.0
@export_range(0.0, 16.0, 0.5) var padding: float = 3.0
@export_range(0, 1000000, 1) var shape_seed: int = 17
var _mark_strength: float = 0.0
func _ready() -> void:
mouse_filter = Control.MOUSE_FILTER_IGNORE
func set_mark_strength(strength: float) -> void:
_mark_strength = clampf(strength, 0.0, 1.0)
visible = _mark_strength > 0.001
queue_redraw()
func _draw() -> void:
if _mark_strength <= 0.001:
return
var center: Vector2 = size * 0.5
var radius := Vector2(
maxf(size.x * 0.5 - padding, 1.0),
maxf(size.y * 0.5 - padding, 1.0),
)
var primary := _build_rough_loop(center, radius, 0)
var secondary := _build_rough_loop(
center + Vector2(0.7, -0.45),
radius - Vector2(1.2, 0.8),
41,
)
var primary_color: Color = ink_color
primary_color.a *= _mark_strength
var secondary_color: Color = ink_color
secondary_color.a *= _mark_strength * 0.36
draw_polyline(primary, primary_color, stroke_width, true)
draw_polyline(secondary, secondary_color, maxf(stroke_width * 0.62, 0.8), true)
func _build_rough_loop(
center: Vector2,
radius: Vector2,
seed_offset: int,
) -> PackedVector2Array:
const POINT_COUNT: int = 26
var points := PackedVector2Array()
for index: int in POINT_COUNT:
var angle: float = TAU * float(index) / float(POINT_COUNT)
var wobble: float = (
sin(float(shape_seed + seed_offset) * 0.73 + float(index) * 2.17)
+ sin(float(shape_seed + seed_offset) * 0.31 + float(index) * 4.03)
* 0.45
)
var radial_scale: float = 1.0 + wobble * 0.018
points.append(
center
+ Vector2(cos(angle), sin(angle)) * radius * radial_scale
)
points.append(points[0])
return points

View file

@ -0,0 +1 @@
uid://dwh3kpogaelxo

View file

@ -162,9 +162,9 @@ func _apply_layout() -> void:
available_size.y - reference_size.y * presentation_scale
)
var field_size := (
Vector2(600.0, 82.0)
Vector2(580.0, 82.0)
if _compact_layout
else Vector2(820.0, 104.0)
else Vector2(790.0, 104.0)
)
_bubble_field.size = field_size
_bubble_field.position = Vector2(

View file

@ -37,73 +37,73 @@ mouse_filter = 2
[node name="BubbleField" type="Control" parent="ResponsiveHotbarStage/HotbarPresentationScaleRoot"]
unique_name_in_owner = true
layout_mode = 0
offset_left = 230.0
offset_left = 245.0
offset_top = 608.0
offset_right = 1050.0
offset_right = 1035.0
offset_bottom = 712.0
mouse_filter = 2
[node name="Slot1" parent="ResponsiveHotbarStage/HotbarPresentationScaleRoot/BubbleField" instance=ExtResource("3_slot")]
layout_mode = 0
slot_index = 0
desktop_anchor = Vector2(58, 49)
compact_anchor = Vector2(52, 42)
desktop_anchor = Vector2(55, 49)
compact_anchor = Vector2(50, 42)
motion_phase = 0.15
[node name="Slot2" parent="ResponsiveHotbarStage/HotbarPresentationScaleRoot/BubbleField" instance=ExtResource("3_slot")]
layout_mode = 0
slot_index = 1
desktop_anchor = Vector2(146, 53)
compact_anchor = Vector2(114, 46)
desktop_anchor = Vector2(140, 53)
compact_anchor = Vector2(110, 46)
motion_phase = 0.82
[node name="Slot3" parent="ResponsiveHotbarStage/HotbarPresentationScaleRoot/BubbleField" instance=ExtResource("3_slot")]
layout_mode = 0
slot_index = 2
desktop_anchor = Vector2(234, 57)
compact_anchor = Vector2(176, 50)
desktop_anchor = Vector2(225, 57)
compact_anchor = Vector2(170, 50)
motion_phase = 1.49
[node name="Slot4" parent="ResponsiveHotbarStage/HotbarPresentationScaleRoot/BubbleField" instance=ExtResource("3_slot")]
layout_mode = 0
slot_index = 3
desktop_anchor = Vector2(322, 60)
compact_anchor = Vector2(238, 53)
desktop_anchor = Vector2(310, 60)
compact_anchor = Vector2(230, 53)
motion_phase = 2.16
[node name="Slot5" parent="ResponsiveHotbarStage/HotbarPresentationScaleRoot/BubbleField" instance=ExtResource("3_slot")]
layout_mode = 0
slot_index = 4
desktop_anchor = Vector2(410, 62)
compact_anchor = Vector2(300, 55)
desktop_anchor = Vector2(395, 62)
compact_anchor = Vector2(290, 55)
motion_phase = 2.83
[node name="Slot6" parent="ResponsiveHotbarStage/HotbarPresentationScaleRoot/BubbleField" instance=ExtResource("3_slot")]
layout_mode = 0
slot_index = 5
desktop_anchor = Vector2(498, 60)
compact_anchor = Vector2(362, 53)
desktop_anchor = Vector2(480, 60)
compact_anchor = Vector2(350, 53)
motion_phase = 3.5
[node name="Slot7" parent="ResponsiveHotbarStage/HotbarPresentationScaleRoot/BubbleField" instance=ExtResource("3_slot")]
layout_mode = 0
slot_index = 6
desktop_anchor = Vector2(586, 57)
compact_anchor = Vector2(424, 50)
desktop_anchor = Vector2(565, 57)
compact_anchor = Vector2(410, 50)
motion_phase = 4.17
[node name="Slot8" parent="ResponsiveHotbarStage/HotbarPresentationScaleRoot/BubbleField" instance=ExtResource("3_slot")]
layout_mode = 0
slot_index = 7
desktop_anchor = Vector2(674, 53)
compact_anchor = Vector2(486, 46)
desktop_anchor = Vector2(650, 53)
compact_anchor = Vector2(470, 46)
motion_phase = 4.84
[node name="Slot9" parent="ResponsiveHotbarStage/HotbarPresentationScaleRoot/BubbleField" instance=ExtResource("3_slot")]
layout_mode = 0
slot_index = 8
desktop_anchor = Vector2(762, 49)
compact_anchor = Vector2(548, 42)
desktop_anchor = Vector2(735, 49)
compact_anchor = Vector2(530, 42)
motion_phase = 5.51
[node name="SelectedItemLabel" type="Label" parent="ResponsiveHotbarStage/HotbarPresentationScaleRoot"]

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff