Add fish silhouettes to Logbook
This commit is contained in:
parent
51ce214a25
commit
3dfa6b221e
5 changed files with 173 additions and 33 deletions
|
|
@ -21,6 +21,11 @@ func _run() -> void:
|
||||||
await process_frame
|
await process_frame
|
||||||
assert(bool(main.get("_gameplay_started")))
|
assert(bool(main.get("_gameplay_started")))
|
||||||
_validate_save_round_trip(main, save_manager)
|
_validate_save_round_trip(main, save_manager)
|
||||||
|
var player := main.get("_player") as Player
|
||||||
|
var no_catches: Array[FishCatch] = []
|
||||||
|
var no_discoveries: Array[StringName] = []
|
||||||
|
assert(player.inventory.replace_all_catches(no_catches, 1))
|
||||||
|
assert(player.collection_log.replace_discovered_ids(no_discoveries))
|
||||||
|
|
||||||
var game_ui := main.get_node("%GameUI") as GameUI
|
var game_ui := main.get_node("%GameUI") as GameUI
|
||||||
var player_menu := game_ui.get_node("%PlayerMenu") as PlayerMenu
|
var player_menu := game_ui.get_node("%PlayerMenu") as PlayerMenu
|
||||||
|
|
@ -54,7 +59,6 @@ func _run() -> void:
|
||||||
logbook.call("_select_category", LogbookCatalog.Category.OTHER)
|
logbook.call("_select_category", LogbookCatalog.Category.OTHER)
|
||||||
await create_timer(0.25).timeout
|
await create_timer(0.25).timeout
|
||||||
assert((logbook.get("_entry_buttons") as Dictionary).size() == 4)
|
assert((logbook.get("_entry_buttons") as Dictionary).size() == 4)
|
||||||
var player := main.get("_player") as Player
|
|
||||||
player.collection_log.mark_discovered(&"bluegill")
|
player.collection_log.mark_discovered(&"bluegill")
|
||||||
await process_frame
|
await process_frame
|
||||||
logbook.call("_select_entry", &"bluegill", &"bluegill")
|
logbook.call("_select_entry", &"bluegill", &"bluegill")
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ const FishCatchType = preload("res://fish/fish_catch.gd")
|
||||||
const FishInventoryType = preload("res://inventory/fish_inventory.gd")
|
const FishInventoryType = preload("res://inventory/fish_inventory.gd")
|
||||||
const FishPoolType = preload("res://fish/fish_pool.gd")
|
const FishPoolType = preload("res://fish/fish_pool.gd")
|
||||||
const CollectionLogType = preload("res://collection/collection_log.gd")
|
const CollectionLogType = preload("res://collection/collection_log.gd")
|
||||||
|
const FishDataType = preload("res://fish/fish_data.gd")
|
||||||
const LogbookPageScene = preload("res://ui/logbook_page.tscn")
|
const LogbookPageScene = preload("res://ui/logbook_page.tscn")
|
||||||
const CatalogResource: FishPoolType = preload(
|
const CatalogResource: FishPoolType = preload(
|
||||||
"res://fish/pools/fish_catalog.tres"
|
"res://fish/pools/fish_catalog.tres"
|
||||||
|
|
@ -75,30 +76,63 @@ func _validate_page() -> void:
|
||||||
page.activate()
|
page.activate()
|
||||||
await process_frame
|
await process_frame
|
||||||
|
|
||||||
|
var shared_material: Material
|
||||||
|
var silhouette_count: int = 0
|
||||||
|
for category: LogbookCatalog.Category in [
|
||||||
|
LogbookCatalog.Category.FRESH_WATER,
|
||||||
|
LogbookCatalog.Category.OTHER,
|
||||||
|
]:
|
||||||
|
page.call("_select_category", category)
|
||||||
|
await create_timer(0.25).timeout
|
||||||
var entries: Dictionary = page.get("_entry_buttons")
|
var entries: Dictionary = page.get("_entry_buttons")
|
||||||
assert(entries.size() == 4)
|
assert(entries.size() == 4)
|
||||||
for entry_value: Variant in entries.values():
|
for fish: FishDataType in LogbookCatalog.ordered_species(
|
||||||
var entry := entry_value as Button
|
CatalogResource.candidates
|
||||||
|
):
|
||||||
|
if LogbookCatalog.category_for(fish) != category:
|
||||||
|
continue
|
||||||
|
var unknown_key := StringName(
|
||||||
|
"unknown_%d" % LogbookCatalog.catalog_number(fish.id)
|
||||||
|
)
|
||||||
|
var entry := entries.get(unknown_key) as Button
|
||||||
assert(entry != null)
|
assert(entry != null)
|
||||||
assert(entry.text.contains("???"))
|
assert(entry.text.is_empty())
|
||||||
assert(entry.tooltip_text.is_empty())
|
assert(entry.tooltip_text.is_empty())
|
||||||
assert(entry.icon == null)
|
assert(entry.icon == null)
|
||||||
assert(entry.accessibility_name == "Unknown catalog entry")
|
assert(entry.accessibility_name == "Unknown catalog entry")
|
||||||
for fish in CatalogResource.candidates:
|
assert(_has_visible_unknown_name(entry))
|
||||||
assert(not entry.text.contains(fish.display_name))
|
var portrait := _find_unknown_portrait(entry)
|
||||||
|
assert(portrait != null)
|
||||||
page.call(
|
assert(portrait.texture == fish.display_texture)
|
||||||
"_select_category", LogbookCatalog.Category.FRESH_WATER
|
assert(
|
||||||
|
portrait.expand_mode
|
||||||
|
== TextureRect.EXPAND_IGNORE_SIZE
|
||||||
)
|
)
|
||||||
await create_timer(0.25).timeout
|
assert(
|
||||||
assert((page.get("_entry_buttons") as Dictionary).size() == 4)
|
portrait.stretch_mode
|
||||||
for entry_value: Variant in (
|
== TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
||||||
page.get("_entry_buttons") as Dictionary
|
)
|
||||||
).values():
|
assert(portrait.material is ShaderMaterial)
|
||||||
var unknown_catfish := entry_value as Button
|
if shared_material == null:
|
||||||
assert(unknown_catfish != null)
|
shared_material = portrait.material
|
||||||
assert(unknown_catfish.text.contains("???"))
|
else:
|
||||||
assert(unknown_catfish.icon == null)
|
assert(portrait.material == shared_material)
|
||||||
|
assert(_texture_has_transparency(portrait.texture))
|
||||||
|
silhouette_count += 1
|
||||||
|
for candidate: FishDataType in CatalogResource.candidates:
|
||||||
|
assert(not entry.text.contains(candidate.display_name))
|
||||||
|
assert(
|
||||||
|
not entry.tooltip_text.contains(
|
||||||
|
candidate.display_name
|
||||||
|
)
|
||||||
|
)
|
||||||
|
assert(
|
||||||
|
not entry.accessibility_name.contains(
|
||||||
|
candidate.display_name
|
||||||
|
)
|
||||||
|
)
|
||||||
|
assert(silhouette_count == 8)
|
||||||
|
|
||||||
page.call("_select_category", LogbookCatalog.Category.SALT_WATER)
|
page.call("_select_category", LogbookCatalog.Category.SALT_WATER)
|
||||||
await create_timer(0.25).timeout
|
await create_timer(0.25).timeout
|
||||||
assert((page.get("_entry_buttons") as Dictionary).is_empty())
|
assert((page.get("_entry_buttons") as Dictionary).is_empty())
|
||||||
|
|
@ -110,13 +144,20 @@ func _validate_page() -> void:
|
||||||
await create_timer(0.25).timeout
|
await create_timer(0.25).timeout
|
||||||
|
|
||||||
var bluegill = CatalogResource.get_fish_by_id(&"bluegill")
|
var bluegill = CatalogResource.get_fish_by_id(&"bluegill")
|
||||||
|
page.call("_select_entry", &"unknown_1", StringName())
|
||||||
|
assert(
|
||||||
|
(page.get("_entry_buttons") as Dictionary)
|
||||||
|
.get(&"unknown_1") != null
|
||||||
|
)
|
||||||
collection.mark_discovered(&"bluegill")
|
collection.mark_discovered(&"bluegill")
|
||||||
await process_frame
|
await process_frame
|
||||||
entries = page.get("_entry_buttons")
|
var entries: Dictionary = page.get("_entry_buttons")
|
||||||
var known := entries.get(&"bluegill") as Button
|
var known := entries.get(&"bluegill") as Button
|
||||||
assert(known != null)
|
assert(known != null)
|
||||||
assert(known.text == bluegill.display_name)
|
assert(known.text == bluegill.display_name)
|
||||||
assert(known.icon == bluegill.display_texture)
|
assert(known.icon == bluegill.display_texture)
|
||||||
|
assert(_find_unknown_portrait(known) == null)
|
||||||
|
assert(known.button_pressed)
|
||||||
|
|
||||||
var fish_catch := FishCatchType.new()
|
var fish_catch := FishCatchType.new()
|
||||||
fish_catch.fish = bluegill
|
fish_catch.fish = bluegill
|
||||||
|
|
@ -151,3 +192,28 @@ func _detail_text(page: LogbookPage) -> String:
|
||||||
for node: Node in detail_body.find_children("*", "Label", true, false):
|
for node: Node in detail_body.find_children("*", "Label", true, false):
|
||||||
values.append((node as Label).text)
|
values.append((node as Label).text)
|
||||||
return "\n".join(values)
|
return "\n".join(values)
|
||||||
|
|
||||||
|
|
||||||
|
func _find_unknown_portrait(entry: Button) -> TextureRect:
|
||||||
|
var pending: Array[Node] = [entry]
|
||||||
|
while not pending.is_empty():
|
||||||
|
var node: Node = pending.pop_back()
|
||||||
|
if node is TextureRect:
|
||||||
|
return node as TextureRect
|
||||||
|
pending.append_array(node.get_children())
|
||||||
|
return null
|
||||||
|
|
||||||
|
|
||||||
|
func _has_visible_unknown_name(entry: Button) -> bool:
|
||||||
|
var pending: Array[Node] = [entry]
|
||||||
|
while not pending.is_empty():
|
||||||
|
var node: Node = pending.pop_back()
|
||||||
|
if node is Label and (node as Label).text == "???":
|
||||||
|
return true
|
||||||
|
pending.append_array(node.get_children())
|
||||||
|
return false
|
||||||
|
|
||||||
|
|
||||||
|
func _texture_has_transparency(texture: Texture2D) -> bool:
|
||||||
|
var image: Image = texture.get_image()
|
||||||
|
return image != null and image.detect_alpha() != Image.ALPHA_NONE
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,9 @@ const CollectionLogType = preload("res://collection/collection_log.gd")
|
||||||
const FishDataType = preload("res://fish/fish_data.gd")
|
const FishDataType = preload("res://fish/fish_data.gd")
|
||||||
const FishInventoryType = preload("res://inventory/fish_inventory.gd")
|
const FishInventoryType = preload("res://inventory/fish_inventory.gd")
|
||||||
const FishPoolType = preload("res://fish/fish_pool.gd")
|
const FishPoolType = preload("res://fish/fish_pool.gd")
|
||||||
|
const SILHOUETTE_SHADER: Shader = preload(
|
||||||
|
"res://ui/logbook_silhouette.gdshader"
|
||||||
|
)
|
||||||
|
|
||||||
const DETAIL_FADE_DURATION: float = 0.12
|
const DETAIL_FADE_DURATION: float = 0.12
|
||||||
const CATEGORY_FADE_DURATION: float = UIMotion.UTILITY_EXIT_DURATION
|
const CATEGORY_FADE_DURATION: float = UIMotion.UTILITY_EXIT_DURATION
|
||||||
|
|
@ -26,6 +29,7 @@ var _detail_generation: int = 0
|
||||||
var _detail_tween: Tween
|
var _detail_tween: Tween
|
||||||
var _category_generation: int = 0
|
var _category_generation: int = 0
|
||||||
var _category_tween: Tween
|
var _category_tween: Tween
|
||||||
|
var _silhouette_material: ShaderMaterial
|
||||||
|
|
||||||
var _category_tabs: Array[Button] = []
|
var _category_tabs: Array[Button] = []
|
||||||
var _catalog_scroll: ScrollContainer
|
var _catalog_scroll: ScrollContainer
|
||||||
|
|
@ -35,6 +39,8 @@ var _detail_body: VBoxContainer
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
|
_silhouette_material = ShaderMaterial.new()
|
||||||
|
_silhouette_material.shader = SILHOUETTE_SHADER
|
||||||
_build_interface()
|
_build_interface()
|
||||||
resized.connect(_update_responsive_layout)
|
resized.connect(_update_responsive_layout)
|
||||||
_update_responsive_layout()
|
_update_responsive_layout()
|
||||||
|
|
@ -225,7 +231,7 @@ func _refresh_catalog() -> void:
|
||||||
if LogbookCatalog.category_for(fish) != _category:
|
if LogbookCatalog.category_for(fish) != _category:
|
||||||
continue
|
continue
|
||||||
var discovered: bool = _collection_log.has_discovered(fish.id)
|
var discovered: bool = _collection_log.has_discovered(fish.id)
|
||||||
var entry: Button = _make_entry(fish if discovered else null)
|
var entry: Button = _make_entry(fish, discovered)
|
||||||
var selection_key: StringName = (
|
var selection_key: StringName = (
|
||||||
fish.id if discovered else _unknown_selection_key(fish)
|
fish.id if discovered else _unknown_selection_key(fish)
|
||||||
)
|
)
|
||||||
|
|
@ -263,9 +269,9 @@ func _refresh_catalog() -> void:
|
||||||
set_interactive(_interactive)
|
set_interactive(_interactive)
|
||||||
|
|
||||||
|
|
||||||
func _make_entry(fish: FishDataType) -> Button:
|
func _make_entry(fish: FishDataType, discovered: bool) -> Button:
|
||||||
var entry := Button.new()
|
var entry := Button.new()
|
||||||
entry.custom_minimum_size = Vector2(220, 122)
|
entry.custom_minimum_size = Vector2(220, 138)
|
||||||
entry.toggle_mode = true
|
entry.toggle_mode = true
|
||||||
entry.clip_text = true
|
entry.clip_text = true
|
||||||
entry.add_theme_font_override("font", UtilityPageStyle.TuffyFont)
|
entry.add_theme_font_override("font", UtilityPageStyle.TuffyFont)
|
||||||
|
|
@ -277,10 +283,11 @@ func _make_entry(fish: FishDataType) -> Button:
|
||||||
entry.add_theme_stylebox_override("hover", _entry_style(true))
|
entry.add_theme_stylebox_override("hover", _entry_style(true))
|
||||||
entry.add_theme_stylebox_override("focus", _entry_style(true))
|
entry.add_theme_stylebox_override("focus", _entry_style(true))
|
||||||
entry.add_theme_stylebox_override("pressed", _entry_style(true))
|
entry.add_theme_stylebox_override("pressed", _entry_style(true))
|
||||||
if fish == null:
|
if not discovered:
|
||||||
entry.text = "?\n???\nCatch this creature\nto learn more."
|
entry.text = ""
|
||||||
entry.tooltip_text = ""
|
entry.tooltip_text = ""
|
||||||
entry.accessibility_name = "Unknown catalog entry"
|
entry.accessibility_name = "Unknown catalog entry"
|
||||||
|
_add_unknown_entry_content(entry, fish.display_texture)
|
||||||
else:
|
else:
|
||||||
entry.text = fish.display_name
|
entry.text = fish.display_name
|
||||||
entry.icon = fish.display_texture
|
entry.icon = fish.display_texture
|
||||||
|
|
@ -292,6 +299,56 @@ func _make_entry(fish: FishDataType) -> Button:
|
||||||
return entry
|
return entry
|
||||||
|
|
||||||
|
|
||||||
|
func _add_unknown_entry_content(
|
||||||
|
entry: Button,
|
||||||
|
portrait: Texture2D,
|
||||||
|
) -> void:
|
||||||
|
var content_margin := MarginContainer.new()
|
||||||
|
content_margin.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||||
|
content_margin.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
||||||
|
content_margin.add_theme_constant_override("margin_left", 7)
|
||||||
|
content_margin.add_theme_constant_override("margin_top", 7)
|
||||||
|
content_margin.add_theme_constant_override("margin_right", 7)
|
||||||
|
content_margin.add_theme_constant_override("margin_bottom", 7)
|
||||||
|
entry.add_child(content_margin)
|
||||||
|
|
||||||
|
var content := VBoxContainer.new()
|
||||||
|
content.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||||
|
content.add_theme_constant_override("separation", 2)
|
||||||
|
content_margin.add_child(content)
|
||||||
|
|
||||||
|
var portrait_view := TextureRect.new()
|
||||||
|
portrait_view.custom_minimum_size = Vector2(0.0, 64.0)
|
||||||
|
portrait_view.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||||
|
portrait_view.texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST
|
||||||
|
portrait_view.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
||||||
|
portrait_view.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
||||||
|
portrait_view.texture = portrait
|
||||||
|
portrait_view.material = _silhouette_material
|
||||||
|
content.add_child(portrait_view)
|
||||||
|
|
||||||
|
var unknown_name := Label.new()
|
||||||
|
unknown_name.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||||
|
unknown_name.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||||
|
unknown_name.text = "???"
|
||||||
|
unknown_name.add_theme_font_override("font", UtilityPageStyle.TuffyFont)
|
||||||
|
unknown_name.add_theme_font_size_override("font_size", 18)
|
||||||
|
unknown_name.add_theme_color_override("font_color", INK)
|
||||||
|
content.add_child(unknown_name)
|
||||||
|
|
||||||
|
var discovery_hint := Label.new()
|
||||||
|
discovery_hint.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||||
|
discovery_hint.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||||
|
discovery_hint.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||||
|
discovery_hint.text = "Catch this creature to learn more."
|
||||||
|
discovery_hint.add_theme_font_override(
|
||||||
|
"font", UtilityPageStyle.TuffyFont
|
||||||
|
)
|
||||||
|
discovery_hint.add_theme_font_size_override("font_size", 12)
|
||||||
|
discovery_hint.add_theme_color_override("font_color", MUTED_INK)
|
||||||
|
content.add_child(discovery_hint)
|
||||||
|
|
||||||
|
|
||||||
func _select_category(category: LogbookCatalog.Category) -> void:
|
func _select_category(category: LogbookCatalog.Category) -> void:
|
||||||
if category == _category:
|
if category == _category:
|
||||||
return
|
return
|
||||||
|
|
@ -544,8 +601,12 @@ func _refresh_selection_styles() -> void:
|
||||||
|
|
||||||
|
|
||||||
func _on_fish_discovered(fish_id: StringName) -> void:
|
func _on_fish_discovered(fish_id: StringName) -> void:
|
||||||
if _catalog == null or _catalog.get_fish_by_id(fish_id) == null:
|
if _catalog == null:
|
||||||
return
|
return
|
||||||
|
var fish: FishDataType = _catalog.get_fish_by_id(fish_id)
|
||||||
|
if fish == null:
|
||||||
|
return
|
||||||
|
if _selected_entry_key == _unknown_selection_key(fish):
|
||||||
_selected_id = fish_id
|
_selected_id = fish_id
|
||||||
_selected_entry_key = fish_id
|
_selected_entry_key = fish_id
|
||||||
_refresh_catalog()
|
_refresh_catalog()
|
||||||
|
|
|
||||||
8
ui/logbook_silhouette.gdshader
Normal file
8
ui/logbook_silhouette.gdshader
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
shader_type canvas_item;
|
||||||
|
|
||||||
|
uniform vec4 silhouette_color : source_color = vec4(0.22, 0.23, 0.24, 1.0);
|
||||||
|
|
||||||
|
void fragment() {
|
||||||
|
vec4 source = texture(TEXTURE, UV);
|
||||||
|
COLOR = vec4(silhouette_color.rgb, source.a * silhouette_color.a);
|
||||||
|
}
|
||||||
1
ui/logbook_silhouette.gdshader.uid
Normal file
1
ui/logbook_silhouette.gdshader.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://1lqrwon78hwm
|
||||||
Loading…
Add table
Add a link
Reference in a new issue