Improve UI scaling and fishing commerce
This commit is contained in:
parent
2de96dd7bb
commit
6b8c3eb2f7
29 changed files with 1515 additions and 817 deletions
|
|
@ -60,6 +60,7 @@ var _send_pending: bool = false
|
|||
var _pending_send_body: String = ""
|
||||
var _prior_movement: bool = true
|
||||
var _prior_camera: bool = true
|
||||
var _output_scale: float = 1.0
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
|
|
@ -563,6 +564,10 @@ func _set_presentation_state(
|
|||
_refresh_visibility()
|
||||
|
||||
|
||||
func set_output_scale(output_scale: float) -> void:
|
||||
_output_scale = maxf(output_scale, 0.001)
|
||||
|
||||
|
||||
func _refresh_handle_labels(state: PresentationState) -> void:
|
||||
var collapsed := state == PresentationState.COLLAPSED
|
||||
var height_state := _visible_state_before_collapse if collapsed else state
|
||||
|
|
@ -632,7 +637,9 @@ func _update_speech() -> void:
|
|||
if camera.is_position_behind(world_position):
|
||||
bubble.hide()
|
||||
continue
|
||||
var screen_position := camera.unproject_position(world_position)
|
||||
var screen_position := (
|
||||
camera.unproject_position(world_position) / _output_scale
|
||||
)
|
||||
var viewport_size := get_viewport_rect().size
|
||||
if (
|
||||
screen_position.x < -80.0
|
||||
|
|
|
|||
|
|
@ -8,7 +8,8 @@ const CONTENT_MARGIN_RIGHT := 18.0
|
|||
const CONTENT_MARGIN_BOTTOM := 16.0
|
||||
const HANDWRITTEN_FONT: Font = preload("res://ui/fonts/seattle_avenue.otf")
|
||||
const NOTEPAD_TEXTURE: Texture2D = preload("res://art/ui/ui_notepad.png")
|
||||
const NOTEPAD_ART_SCALE := 1.1
|
||||
const NOTEPAD_CANONICAL_OVERSCAN: float = 1.2
|
||||
const NOTEPAD_ART_OFFSET := Vector2(10.0, 20.0)
|
||||
|
||||
@export var title_text := "notes"
|
||||
@export var inset_content := true
|
||||
|
|
@ -34,17 +35,7 @@ static func apply_handwritten_to(root: Control) -> void:
|
|||
|
||||
|
||||
func _draw() -> void:
|
||||
var texture_size := NOTEPAD_TEXTURE.get_size()
|
||||
var uniform_scale := minf(
|
||||
size.x / texture_size.x,
|
||||
size.y / texture_size.y,
|
||||
) * NOTEPAD_ART_SCALE
|
||||
var rendered_size := texture_size * uniform_scale
|
||||
var rendered_rect := Rect2(
|
||||
(size - rendered_size) * 0.5,
|
||||
rendered_size,
|
||||
)
|
||||
draw_texture_rect(NOTEPAD_TEXTURE, rendered_rect, false)
|
||||
draw_texture_rect(NOTEPAD_TEXTURE, get_art_rect(), false)
|
||||
|
||||
var font: Font = HANDWRITTEN_FONT
|
||||
draw_string(
|
||||
|
|
@ -58,6 +49,34 @@ func _draw() -> void:
|
|||
)
|
||||
|
||||
|
||||
func get_art_rect() -> Rect2:
|
||||
return get_art_rect_for_host(size)
|
||||
|
||||
|
||||
static func get_art_rect_for_host(host_size: Vector2) -> Rect2:
|
||||
# Source pixels establish the artwork aspect ratio and sampling quality. The
|
||||
# canonical host rect, not the source dimensions, owns its displayed size.
|
||||
var source_size: Vector2 = NOTEPAD_TEXTURE.get_size()
|
||||
if (
|
||||
host_size.x <= 0.0
|
||||
or host_size.y <= 0.0
|
||||
or source_size.x <= 0.0
|
||||
or source_size.y <= 0.0
|
||||
):
|
||||
return Rect2()
|
||||
var fit_scale: float = minf(
|
||||
host_size.x / source_size.x,
|
||||
host_size.y / source_size.y,
|
||||
)
|
||||
var rendered_size: Vector2 = (
|
||||
source_size * fit_scale * NOTEPAD_CANONICAL_OVERSCAN
|
||||
)
|
||||
return Rect2(
|
||||
(host_size - rendered_size) * 0.5 + NOTEPAD_ART_OFFSET,
|
||||
rendered_size,
|
||||
)
|
||||
|
||||
|
||||
static func make_layout_style(with_content_margins: bool = true) -> StyleBoxFlat:
|
||||
var paper := StyleBoxFlat.new()
|
||||
paper.bg_color = Color.TRANSPARENT
|
||||
|
|
|
|||
|
|
@ -4,10 +4,6 @@ extends Control
|
|||
const INPUT_OWNER: StringName = &"fishing_shop"
|
||||
const MAIN_SHOP_BUYER_ID: StringName = &"main_fishing_shop"
|
||||
const FishBuyerProfileType = preload("res://economy/fish_buyer_profile.gd")
|
||||
const FishCatchType = preload("res://fish/fish_catch.gd")
|
||||
const FishInventoryType = preload("res://inventory/fish_inventory.gd")
|
||||
const FishSaleResultType = preload("res://economy/fish_sale_result.gd")
|
||||
const FishSaleServiceType = preload("res://economy/fish_sale_service.gd")
|
||||
const PlayerWalletType = preload("res://economy/player_wallet.gd")
|
||||
const FishingShopStockType = preload("res://economy/fishing_shop_stock.gd")
|
||||
const ItemCatalogType = preload("res://items/item_catalog.gd")
|
||||
|
|
@ -24,11 +20,12 @@ const PlayerCoolerCapacityType = preload(
|
|||
const ShopInteractionType = preload(
|
||||
"res://world/fishing_shop_interaction.gd"
|
||||
)
|
||||
const FishBatchSelectionType = preload(
|
||||
"res://ui/fish_batch_selection.gd"
|
||||
)
|
||||
const UtilityPageStyleType = preload("res://ui/utility_page_style.gd")
|
||||
|
||||
signal menu_visibility_changed(is_open: bool)
|
||||
signal sell_fish_requested
|
||||
signal shop_cooler_return_requested
|
||||
signal shop_cooler_confirmation_cancel_requested
|
||||
|
||||
enum CloseReason {
|
||||
USER,
|
||||
|
|
@ -39,17 +36,12 @@ enum CloseReason {
|
|||
}
|
||||
|
||||
@onready var _wallet_label: Label = %WalletLabel
|
||||
@onready var _fish_sales: VBoxContainer = (
|
||||
$ShopPanel/Margin/Layout/Body/FishSales
|
||||
)
|
||||
@onready var _fish_list: ItemList = %FishList
|
||||
@onready var _sales_title: Label = %SalesTitle
|
||||
@onready var _fish_empty: Label = %FishEmpty
|
||||
@onready var _fish_texture: TextureRect = %FishTexture
|
||||
@onready var _fish_name: Label = %FishName
|
||||
@onready var _fish_details: Label = %FishDetails
|
||||
@onready var _selection_summary: Label = %SelectionSummary
|
||||
@onready var _sell_button: Button = %SellButton
|
||||
@onready var _shop_panel: PanelContainer = %ShopPanel
|
||||
@onready var _shop_cooler_page: Control = %ShopCoolerPage
|
||||
@onready var _shop_cooler_mount: Control = %ShopCoolerMount
|
||||
@onready var _back_to_shop_button: Button = %BackToShopButton
|
||||
@onready var _buy_mode_button: Button = %BuyModeButton
|
||||
@onready var _sell_mode_button: Button = %SellModeButton
|
||||
@onready var _feedback: Label = %Feedback
|
||||
@onready var _reel_level: Label = %ReelLevel
|
||||
@onready var _reel_effect: Label = %ReelEffect
|
||||
|
|
@ -64,15 +56,9 @@ enum CloseReason {
|
|||
@onready var _cooler_effect: Label = %CoolerEffect
|
||||
@onready var _cooler_cost: Label = %CoolerCost
|
||||
@onready var _cooler_purchase: Button = %CoolerPurchase
|
||||
@onready var _confirmation: PanelContainer = %SaleConfirmation
|
||||
@onready var _confirmation_text: Label = %ConfirmationText
|
||||
@onready var _confirm_sale: Button = %ConfirmSale
|
||||
@onready var _cancel_sale: Button = %CancelSale
|
||||
|
||||
var _player: PlayerType
|
||||
var _inventory: FishInventoryType
|
||||
var _wallet: PlayerWalletType
|
||||
var _sale_service: FishSaleServiceType
|
||||
var _buyer: FishBuyerProfileType
|
||||
var _upgrades: PlayerFishingUpgradesType
|
||||
var _fishing_spot: FishingSpotType
|
||||
|
|
@ -80,42 +66,93 @@ var _interaction: ShopInteractionType
|
|||
var _bag: PlayerBagType
|
||||
var _item_catalog: ItemCatalogType
|
||||
var _cooler_capacity: PlayerCoolerCapacityType
|
||||
var _network_session: NetworkSession
|
||||
var _network_shop: NetworkShopService
|
||||
var _fish_selection := FishBatchSelectionType.new()
|
||||
var _confirmation_catch_ids: Array[StringName] = []
|
||||
var _confirmation_generation: int = -1
|
||||
var _prior_movement_enabled: bool = true
|
||||
var _prior_camera_enabled: bool = true
|
||||
var _prior_mouse_mode: Input.MouseMode = Input.MOUSE_MODE_VISIBLE
|
||||
var _snapshot_stored: bool = false
|
||||
var _mouse_snapshot_stored: bool = false
|
||||
var _generation: int = 0
|
||||
var _selection_input_generation: int = 0
|
||||
var _transaction_in_progress: bool = false
|
||||
var _closing: bool = false
|
||||
var _cooler_page_active: bool = false
|
||||
var _cooler_modal_open: bool = false
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
# Catch selling belongs to the Pelican action in the Player Menu. Keep the
|
||||
# legacy shop sales controls out of the active interface.
|
||||
_fish_sales.hide()
|
||||
UtilityPageStyleType.apply_page(self)
|
||||
_apply_shop_styles()
|
||||
%CloseButton.pressed.connect(close_shop)
|
||||
_fish_list.item_selected.connect(_on_fish_selected)
|
||||
_fish_list.item_clicked.connect(_on_fish_clicked)
|
||||
_sell_button.pressed.connect(_open_sale_confirmation)
|
||||
_confirm_sale.pressed.connect(_on_confirm_sale)
|
||||
_cancel_sale.pressed.connect(_close_sale_confirmation)
|
||||
_buy_mode_button.pressed.connect(_focus_buy_page)
|
||||
_sell_mode_button.pressed.connect(_request_shop_cooler)
|
||||
_back_to_shop_button.pressed.connect(shop_cooler_return_requested.emit)
|
||||
_reel_purchase.pressed.connect(_purchase_reel_speed)
|
||||
_barrier_purchase.pressed.connect(_purchase_barrier_power)
|
||||
_cooler_purchase.pressed.connect(_purchase_cooler_capacity)
|
||||
|
||||
|
||||
func _request_shop_cooler() -> void:
|
||||
if _transaction_in_progress:
|
||||
_feedback.text = "Finish the current transaction first."
|
||||
return
|
||||
if not _is_transaction_context_valid():
|
||||
_feedback.text = "The fishing shop is no longer available."
|
||||
return
|
||||
sell_fish_requested.emit()
|
||||
|
||||
|
||||
func _focus_buy_page() -> void:
|
||||
_feedback.text = ""
|
||||
if _supplies_list.get_child_count() > 0:
|
||||
var first_supply := _supplies_list.get_child(0) as Button
|
||||
if first_supply != null and not first_supply.disabled:
|
||||
first_supply.grab_focus()
|
||||
return
|
||||
_reel_purchase.grab_focus()
|
||||
|
||||
|
||||
func _apply_shop_styles() -> void:
|
||||
var shop_panel := $ShopPanel as PanelContainer
|
||||
var shop_panel_style := UtilityPageStyleType.panel_style()
|
||||
shop_panel_style.set_corner_radius_all(24)
|
||||
shop_panel_style.content_margin_left = 0.0
|
||||
shop_panel_style.content_margin_top = 0.0
|
||||
shop_panel_style.content_margin_right = 0.0
|
||||
shop_panel_style.content_margin_bottom = 0.0
|
||||
shop_panel.add_theme_stylebox_override(
|
||||
"panel", shop_panel_style
|
||||
)
|
||||
for panel: PanelContainer in [
|
||||
$ShopPanel/Margin/Layout/Body/Upgrades/ReelCard,
|
||||
$ShopPanel/Margin/Layout/Body/Upgrades/BarrierCard,
|
||||
$ShopPanel/Margin/Layout/Body/Upgrades/CoolerCard,
|
||||
]:
|
||||
panel.add_theme_stylebox_override(
|
||||
"panel", UtilityPageStyleType.row_style()
|
||||
)
|
||||
for button: BaseButton in [
|
||||
%CloseButton,
|
||||
_buy_mode_button,
|
||||
_sell_mode_button,
|
||||
_reel_purchase,
|
||||
_barrier_purchase,
|
||||
_cooler_purchase,
|
||||
_back_to_shop_button,
|
||||
]:
|
||||
UtilityPageStyleType.apply_ocean_button(button)
|
||||
_buy_mode_button.add_theme_stylebox_override(
|
||||
"normal",
|
||||
UtilityPageStyleType.ocean_button_style(
|
||||
UtilityPageStyleType.OCEAN_SELECTED
|
||||
),
|
||||
)
|
||||
_feedback.add_theme_color_override(
|
||||
"font_color", UtilityPageStyleType.OCEAN_TEXT_SECONDARY
|
||||
)
|
||||
|
||||
|
||||
func setup(
|
||||
player: PlayerType,
|
||||
inventory: FishInventoryType,
|
||||
wallet: PlayerWalletType,
|
||||
sale_service: FishSaleServiceType,
|
||||
buyer: FishBuyerProfileType,
|
||||
upgrades: PlayerFishingUpgradesType,
|
||||
fishing_spot: FishingSpotType,
|
||||
|
|
@ -123,13 +160,10 @@ func setup(
|
|||
bag: PlayerBagType,
|
||||
item_catalog: ItemCatalogType,
|
||||
cooler_capacity: PlayerCoolerCapacityType,
|
||||
network_session: NetworkSession,
|
||||
network_shop: NetworkShopService,
|
||||
) -> void:
|
||||
_player = player
|
||||
_inventory = inventory
|
||||
_wallet = wallet
|
||||
_sale_service = sale_service
|
||||
_buyer = buyer
|
||||
_upgrades = upgrades
|
||||
_fishing_spot = fishing_spot
|
||||
|
|
@ -137,7 +171,6 @@ func setup(
|
|||
_bag = bag
|
||||
_item_catalog = item_catalog
|
||||
_cooler_capacity = cooler_capacity
|
||||
_network_session = network_session
|
||||
_network_shop = network_shop
|
||||
if (
|
||||
_network_shop != null
|
||||
|
|
@ -151,9 +184,6 @@ func setup(
|
|||
_network_shop.local_purchase_finished.connect(
|
||||
_on_network_purchase_finished
|
||||
)
|
||||
_fish_selection.clear()
|
||||
if not _inventory.catches_changed.is_connected(_on_inventory_changed):
|
||||
_inventory.catches_changed.connect(_on_inventory_changed)
|
||||
if not _wallet.balance_changed.is_connected(_on_wallet_changed):
|
||||
_wallet.balance_changed.connect(_on_wallet_changed)
|
||||
if not _upgrades.upgrades_changed.is_connected(_on_upgrades_changed):
|
||||
|
|
@ -180,7 +210,6 @@ func open_shop() -> bool:
|
|||
or _buyer.id != MAIN_SHOP_BUYER_ID
|
||||
):
|
||||
return false
|
||||
_generation += 1
|
||||
_closing = false
|
||||
_transaction_in_progress = (
|
||||
_network_shop != null
|
||||
|
|
@ -196,10 +225,10 @@ func open_shop() -> bool:
|
|||
_fishing_spot.set_local_menu_input_suppressed(INPUT_OWNER, true)
|
||||
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
|
||||
_feedback.text = ""
|
||||
_close_sale_confirmation()
|
||||
deactivate_shop_cooler_page()
|
||||
show()
|
||||
_refresh_all()
|
||||
%CloseButton.grab_focus()
|
||||
_buy_mode_button.grab_focus()
|
||||
menu_visibility_changed.emit(true)
|
||||
return true
|
||||
|
||||
|
|
@ -207,13 +236,42 @@ func open_shop() -> bool:
|
|||
func consume_escape() -> bool:
|
||||
if not visible:
|
||||
return false
|
||||
if _confirmation.visible:
|
||||
_close_sale_confirmation()
|
||||
else:
|
||||
close_shop()
|
||||
if _cooler_page_active:
|
||||
if _cooler_modal_open:
|
||||
shop_cooler_confirmation_cancel_requested.emit()
|
||||
else:
|
||||
shop_cooler_return_requested.emit()
|
||||
return true
|
||||
close_shop()
|
||||
return true
|
||||
|
||||
|
||||
func get_shop_cooler_mount() -> Control:
|
||||
return _shop_cooler_mount
|
||||
|
||||
|
||||
func activate_shop_cooler_page() -> void:
|
||||
_cooler_page_active = true
|
||||
_shop_panel.hide()
|
||||
_shop_cooler_page.show()
|
||||
_back_to_shop_button.disabled = false
|
||||
|
||||
|
||||
func deactivate_shop_cooler_page() -> void:
|
||||
_cooler_page_active = false
|
||||
_cooler_modal_open = false
|
||||
_back_to_shop_button.disabled = false
|
||||
_shop_cooler_page.hide()
|
||||
_shop_panel.show()
|
||||
if visible:
|
||||
_buy_mode_button.grab_focus()
|
||||
|
||||
|
||||
func set_shop_cooler_modal_open(is_open: bool) -> void:
|
||||
_cooler_modal_open = is_open
|
||||
_back_to_shop_button.disabled = is_open
|
||||
|
||||
|
||||
func close_shop(
|
||||
reason: CloseReason = CloseReason.USER,
|
||||
restore_controls: bool = true,
|
||||
|
|
@ -221,10 +279,7 @@ func close_shop(
|
|||
if not visible:
|
||||
return
|
||||
_closing = true
|
||||
_generation += 1
|
||||
_transaction_in_progress = false
|
||||
_close_sale_confirmation()
|
||||
_fish_selection.clear()
|
||||
hide()
|
||||
get_viewport().gui_release_focus()
|
||||
if _fishing_spot != null and is_instance_valid(_fishing_spot):
|
||||
|
|
@ -241,6 +296,7 @@ func close_shop(
|
|||
_apply_mouse_close_policy(reason)
|
||||
_closing = false
|
||||
menu_visibility_changed.emit(false)
|
||||
deactivate_shop_cooler_page()
|
||||
|
||||
|
||||
func close_for_range_exit() -> void:
|
||||
|
|
@ -268,8 +324,6 @@ func _refresh_all() -> void:
|
|||
if not is_node_ready():
|
||||
return
|
||||
_refresh_wallet()
|
||||
_refresh_fish_list()
|
||||
_refresh_selected_fish()
|
||||
_refresh_upgrades()
|
||||
_refresh_supplies()
|
||||
_refresh_cooler_capacity()
|
||||
|
|
@ -283,144 +337,6 @@ func _refresh_wallet() -> void:
|
|||
)
|
||||
|
||||
|
||||
func _refresh_fish_list() -> void:
|
||||
_fish_list.clear()
|
||||
var catches: Array[FishCatchType] = (
|
||||
_inventory.get_all_catches() if _inventory != null else []
|
||||
)
|
||||
_sales_title.text = "cooler %d / %d • full base value" % [
|
||||
catches.size(),
|
||||
_cooler_capacity.get_capacity() if _cooler_capacity != null else 0,
|
||||
]
|
||||
catches.sort_custom(
|
||||
func(a: FishCatchType, b: FishCatchType) -> bool:
|
||||
return a.catch_sequence > b.catch_sequence
|
||||
)
|
||||
var visible_ids: Array[StringName] = []
|
||||
for fish_catch: FishCatchType in catches:
|
||||
if fish_catch != null and fish_catch.is_valid():
|
||||
visible_ids.append(fish_catch.catch_id)
|
||||
_fish_selection.set_visible_order(visible_ids)
|
||||
for fish_catch: FishCatchType in catches:
|
||||
if fish_catch == null or not fish_catch.is_valid():
|
||||
continue
|
||||
var marker: String = ""
|
||||
if _fish_selection.is_selected(fish_catch.catch_id):
|
||||
marker += "✓ "
|
||||
if fish_catch.catch_id == _fish_selection.get_focused_id():
|
||||
marker += "◆ "
|
||||
if fish_catch.is_favorited:
|
||||
marker += "★ "
|
||||
var index: int = _fish_list.add_item(
|
||||
"%s%s — %.2f lb"
|
||||
% [marker, fish_catch.fish.display_name, fish_catch.weight_lb],
|
||||
fish_catch.fish.display_texture
|
||||
)
|
||||
_fish_list.set_item_metadata(index, String(fish_catch.catch_id))
|
||||
_fish_list.set_item_tooltip(
|
||||
index,
|
||||
"%s • %s"
|
||||
% [
|
||||
fish_catch.fish.get_rarity_name(),
|
||||
"favorited" if fish_catch.is_favorited else "available",
|
||||
]
|
||||
)
|
||||
_fish_empty.visible = _fish_list.item_count == 0
|
||||
_fish_list.deselect_all()
|
||||
for index: int in range(_fish_list.item_count):
|
||||
var catch_id := StringName(str(_fish_list.get_item_metadata(index)))
|
||||
if _fish_selection.is_selected(catch_id):
|
||||
_fish_list.select(index, false)
|
||||
|
||||
|
||||
func _refresh_selected_fish() -> void:
|
||||
var fish_catch: FishCatchType = _get_selected_catch()
|
||||
_fish_texture.texture = (
|
||||
fish_catch.fish.display_texture if fish_catch != null else null
|
||||
)
|
||||
_fish_name.text = (
|
||||
fish_catch.fish.display_name if fish_catch != null else "select a fish"
|
||||
)
|
||||
if fish_catch == null:
|
||||
_fish_details.text = "choose one individual fish from your cooler."
|
||||
_update_sale_summary()
|
||||
return
|
||||
var individual_preview: FishSaleResultType = (
|
||||
_sale_service.preview_batch([fish_catch.catch_id], _buyer)
|
||||
if _sale_service != null
|
||||
else null
|
||||
)
|
||||
var offer: int = (
|
||||
individual_preview.payout if individual_preview != null else -1
|
||||
)
|
||||
_fish_details.text = (
|
||||
"%.2f lb • %s\nbase value: $%d\nmain-shop offer: $%d%s"
|
||||
% [
|
||||
fish_catch.weight_lb,
|
||||
fish_catch.fish.get_rarity_name(),
|
||||
fish_catch.sale_value,
|
||||
offer,
|
||||
"\nfavorited fish cannot be sold."
|
||||
if fish_catch.is_favorited
|
||||
else "",
|
||||
]
|
||||
)
|
||||
_update_sale_summary()
|
||||
|
||||
|
||||
func _update_sale_summary() -> void:
|
||||
var selected_ids: Array[StringName] = _fish_selection.get_selected_ids()
|
||||
var selected_count: int = selected_ids.size()
|
||||
_sell_button.text = (
|
||||
"sell fish"
|
||||
if selected_count <= 1
|
||||
else "sell %d fish" % selected_count
|
||||
)
|
||||
if selected_count == 0:
|
||||
_selection_summary.text = "no fish selected"
|
||||
_sell_button.disabled = true
|
||||
return
|
||||
if _network_session != null and _network_session.is_joined_client():
|
||||
_selection_summary.text = (
|
||||
"1 fish selected"
|
||||
if selected_count == 1
|
||||
else "%d fish selected" % selected_count
|
||||
)
|
||||
_selection_summary.text += (
|
||||
"\nSell catches to the nearby pelicans."
|
||||
)
|
||||
_sell_button.disabled = true
|
||||
return
|
||||
var preview: FishSaleResultType = (
|
||||
_sale_service.preview_batch(selected_ids, _buyer)
|
||||
if _sale_service != null
|
||||
else null
|
||||
)
|
||||
_selection_summary.text = (
|
||||
"1 fish selected"
|
||||
if selected_count == 1
|
||||
else "%d fish selected" % selected_count
|
||||
)
|
||||
if (
|
||||
preview != null
|
||||
and (
|
||||
preview.is_success()
|
||||
or preview.status == FishSaleResultType.Status.FAVORITED
|
||||
)
|
||||
):
|
||||
_selection_summary.text += "\ntotal offer: $%d" % preview.payout
|
||||
if preview != null and preview.status == FishSaleResultType.Status.FAVORITED:
|
||||
_selection_summary.text += (
|
||||
"\nfavorited fish must be removed from the selection."
|
||||
)
|
||||
_sell_button.disabled = (
|
||||
preview == null
|
||||
or not preview.is_success()
|
||||
or _transaction_in_progress
|
||||
or _closing
|
||||
)
|
||||
|
||||
|
||||
func _refresh_upgrades() -> void:
|
||||
if _upgrades == null:
|
||||
return
|
||||
|
|
@ -516,6 +432,7 @@ func _refresh_supplies() -> void:
|
|||
if _network_shop == null or not _network_shop.can_request_purchase()
|
||||
else item.description
|
||||
)
|
||||
UtilityPageStyleType.apply_ocean_button(button)
|
||||
button.pressed.connect(_purchase_supply.bind(item_id))
|
||||
_supplies_list.add_child(button)
|
||||
|
||||
|
|
@ -549,142 +466,6 @@ func _refresh_cooler_capacity() -> void:
|
|||
_cooler_purchase.text = "purchase"
|
||||
|
||||
|
||||
func _on_fish_selected(index: int) -> void:
|
||||
if index < 0 or index >= _fish_list.item_count:
|
||||
return
|
||||
var input_generation: int = _selection_input_generation
|
||||
call_deferred(
|
||||
"_apply_keyboard_fish_selection",
|
||||
index,
|
||||
input_generation
|
||||
)
|
||||
|
||||
|
||||
func _apply_keyboard_fish_selection(
|
||||
index: int,
|
||||
input_generation: int,
|
||||
) -> void:
|
||||
if (
|
||||
input_generation != _selection_input_generation
|
||||
or index < 0
|
||||
or index >= _fish_list.item_count
|
||||
):
|
||||
return
|
||||
var catch_id := StringName(str(_fish_list.get_item_metadata(index)))
|
||||
_fish_selection.select_only(catch_id)
|
||||
_feedback.text = ""
|
||||
_refresh_fish_list()
|
||||
_refresh_selected_fish()
|
||||
|
||||
|
||||
func _on_fish_clicked(
|
||||
index: int,
|
||||
_position: Vector2,
|
||||
mouse_button_index: int,
|
||||
) -> void:
|
||||
if (
|
||||
mouse_button_index != MOUSE_BUTTON_LEFT
|
||||
or index < 0
|
||||
or index >= _fish_list.item_count
|
||||
):
|
||||
return
|
||||
_selection_input_generation += 1
|
||||
var catch_id := StringName(str(_fish_list.get_item_metadata(index)))
|
||||
_fish_selection.apply_click(
|
||||
catch_id,
|
||||
Input.is_key_pressed(KEY_CTRL),
|
||||
Input.is_key_pressed(KEY_SHIFT)
|
||||
)
|
||||
_feedback.text = ""
|
||||
_refresh_fish_list()
|
||||
_refresh_selected_fish()
|
||||
|
||||
|
||||
func _open_sale_confirmation() -> void:
|
||||
if _network_session != null and _network_session.is_joined_client():
|
||||
_feedback.text = "Sell catches to the nearby pelicans."
|
||||
return
|
||||
var selected_ids: Array[StringName] = _fish_selection.get_selected_ids()
|
||||
if not _is_transaction_context_valid() or selected_ids.is_empty():
|
||||
_feedback.text = "the fish selection is no longer available."
|
||||
_refresh_all()
|
||||
return
|
||||
var preview: FishSaleResultType = _sale_service.preview_batch(
|
||||
selected_ids,
|
||||
_buyer
|
||||
)
|
||||
if not preview.is_success():
|
||||
_feedback.text = (
|
||||
"favorited fish cannot be sold. "
|
||||
+ "remove them from the selection first."
|
||||
if preview.status == FishSaleResultType.Status.FAVORITED
|
||||
else preview.get_message()
|
||||
)
|
||||
return
|
||||
_confirmation_catch_ids = selected_ids.duplicate()
|
||||
_confirmation_generation = _generation
|
||||
_confirmation_text.text = (
|
||||
"sell %d fish to the fishing shop for $%d?"
|
||||
% [preview.fish_count, preview.payout]
|
||||
)
|
||||
_confirmation.show()
|
||||
_cancel_sale.grab_focus()
|
||||
|
||||
|
||||
func _close_sale_confirmation() -> void:
|
||||
_confirmation_catch_ids.clear()
|
||||
_confirmation_generation = -1
|
||||
_confirmation.hide()
|
||||
|
||||
|
||||
func _on_confirm_sale() -> void:
|
||||
if (
|
||||
_transaction_in_progress
|
||||
or (
|
||||
_network_session != null
|
||||
and _network_session.is_joined_client()
|
||||
)
|
||||
):
|
||||
return
|
||||
var transaction_generation: int = _generation
|
||||
var catch_ids: Array[StringName] = _confirmation_catch_ids.duplicate()
|
||||
var confirmation_generation: int = _confirmation_generation
|
||||
_close_sale_confirmation()
|
||||
if (
|
||||
catch_ids.is_empty()
|
||||
or not _is_transaction_context_valid()
|
||||
or transaction_generation != _generation
|
||||
or confirmation_generation != transaction_generation
|
||||
or _buyer.id != MAIN_SHOP_BUYER_ID
|
||||
):
|
||||
_feedback.text = "unable to complete sale."
|
||||
return
|
||||
_transaction_in_progress = true
|
||||
var result: FishSaleResultType = _sale_service.sell_batch(
|
||||
catch_ids,
|
||||
_buyer
|
||||
)
|
||||
_transaction_in_progress = false
|
||||
if (
|
||||
transaction_generation != _generation
|
||||
or not visible
|
||||
):
|
||||
return
|
||||
if result.is_success():
|
||||
_feedback.text = (
|
||||
"fish sold for $%d."
|
||||
if result.fish_count == 1
|
||||
else "%d fish sold for $%d." % [
|
||||
result.fish_count,
|
||||
result.payout,
|
||||
]
|
||||
)
|
||||
_fish_selection.remove_ids(catch_ids)
|
||||
else:
|
||||
_feedback.text = result.get_message()
|
||||
_refresh_all()
|
||||
|
||||
|
||||
func _purchase_reel_speed() -> void:
|
||||
_purchase_upgrade(true)
|
||||
|
||||
|
|
@ -777,13 +558,6 @@ func _on_network_purchase_finished(
|
|||
_refresh_all()
|
||||
|
||||
|
||||
func _get_selected_catch() -> FishCatchType:
|
||||
var focused_id: StringName = _fish_selection.get_focused_id()
|
||||
if _inventory == null or focused_id.is_empty():
|
||||
return null
|
||||
return _inventory.get_catch_by_id(focused_id)
|
||||
|
||||
|
||||
func _is_transaction_context_valid() -> bool:
|
||||
return (
|
||||
visible
|
||||
|
|
@ -798,27 +572,6 @@ func _is_transaction_context_valid() -> bool:
|
|||
)
|
||||
|
||||
|
||||
func _on_inventory_changed() -> void:
|
||||
_refresh_fish_list()
|
||||
if not _confirmation_catch_ids.is_empty():
|
||||
var preview: FishSaleResultType = _sale_service.preview_batch(
|
||||
_confirmation_catch_ids,
|
||||
_buyer
|
||||
)
|
||||
if (
|
||||
_confirmation_generation != _generation
|
||||
or not preview.is_success()
|
||||
):
|
||||
_close_sale_confirmation()
|
||||
_feedback.text = (
|
||||
"favorited fish cannot be sold. "
|
||||
+ "remove them from the selection first."
|
||||
if preview.status == FishSaleResultType.Status.FAVORITED
|
||||
else preview.get_message()
|
||||
)
|
||||
_refresh_selected_fish()
|
||||
|
||||
|
||||
func _on_wallet_changed(_balance: int, _delta: int) -> void:
|
||||
_refresh_wallet()
|
||||
_refresh_upgrades()
|
||||
|
|
@ -839,7 +592,6 @@ func _on_bag_changed() -> void:
|
|||
|
||||
func _on_cooler_capacity_changed(_level: int, _capacity: int) -> void:
|
||||
_refresh_cooler_capacity()
|
||||
_refresh_fish_list()
|
||||
|
||||
|
||||
func _apply_mouse_close_policy(reason: CloseReason) -> void:
|
||||
|
|
|
|||
|
|
@ -19,9 +19,10 @@ grow_horizontal = 2
|
|||
grow_vertical = 2
|
||||
mouse_filter = 2
|
||||
theme = ExtResource("2_theme")
|
||||
theme_override_font_sizes/font_size = 20
|
||||
script = ExtResource("1_script")
|
||||
|
||||
[node name="Dimmer" type="ColorRect" parent="."]
|
||||
[node name="InputBlocker" type="Control" parent="."]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
|
|
@ -29,28 +30,60 @@ anchor_bottom = 1.0
|
|||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
mouse_filter = 0
|
||||
color = Color(0.015, 0.02, 0.03, 0.64)
|
||||
|
||||
[node name="ShopCoolerPage" type="Control" parent="."]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
z_index = 90
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
mouse_filter = 1
|
||||
|
||||
[node name="ShopCoolerMount" type="Control" parent="ShopCoolerPage"]
|
||||
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 = 1
|
||||
|
||||
[node name="BackToShopButton" type="Button" parent="ShopCoolerPage"]
|
||||
unique_name_in_owner = true
|
||||
z_index = 110
|
||||
layout_mode = 0
|
||||
offset_left = 1052.0
|
||||
offset_top = 54.0
|
||||
offset_right = 1218.0
|
||||
offset_bottom = 104.0
|
||||
text = "back to shop"
|
||||
|
||||
[node name="ShopPanel" type="PanelContainer" parent="."]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -560.0
|
||||
offset_top = -320.0
|
||||
offset_right = 560.0
|
||||
offset_bottom = 320.0
|
||||
offset_left = -490.0
|
||||
offset_top = -300.0
|
||||
offset_right = 490.0
|
||||
offset_bottom = 300.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
|
||||
[node name="Margin" type="MarginContainer" parent="ShopPanel"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/margin_left = 16
|
||||
theme_override_constants/margin_top = 14
|
||||
theme_override_constants/margin_top = 12
|
||||
theme_override_constants/margin_right = 16
|
||||
theme_override_constants/margin_bottom = 14
|
||||
theme_override_constants/margin_bottom = 12
|
||||
|
||||
[node name="Layout" type="VBoxContainer" parent="ShopPanel/Margin"]
|
||||
layout_mode = 2
|
||||
|
|
@ -64,7 +97,7 @@ theme_override_constants/separation = 8
|
|||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
text = "fishing shop"
|
||||
theme_override_font_sizes/font_size = 36
|
||||
theme_override_font_sizes/font_size = 32
|
||||
theme_override_colors/font_color = Color(0.208, 0.725, 0.78, 1)
|
||||
|
||||
[node name="CoinIcon" type="TextureRect" parent="ShopPanel/Margin/Layout/Header"]
|
||||
|
|
@ -84,7 +117,24 @@ text = "wallet: $0"
|
|||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
text = "close"
|
||||
custom_minimum_size = Vector2(110, 58)
|
||||
custom_minimum_size = Vector2(104, 48)
|
||||
|
||||
[node name="ModeTabs" type="HBoxContainer" parent="ShopPanel/Margin/Layout"]
|
||||
layout_mode = 2
|
||||
alignment = 1
|
||||
theme_override_constants/separation = 10
|
||||
|
||||
[node name="BuyModeButton" type="Button" parent="ShopPanel/Margin/Layout/ModeTabs"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(180, 42)
|
||||
layout_mode = 2
|
||||
text = "buy gear & supplies"
|
||||
|
||||
[node name="SellModeButton" type="Button" parent="ShopPanel/Margin/Layout/ModeTabs"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(180, 42)
|
||||
layout_mode = 2
|
||||
text = "sell fish"
|
||||
|
||||
[node name="Feedback" type="Label" parent="ShopPanel/Margin/Layout"]
|
||||
unique_name_in_owner = true
|
||||
|
|
@ -98,123 +148,27 @@ layout_mode = 2
|
|||
size_flags_vertical = 3
|
||||
theme_override_constants/separation = 12
|
||||
|
||||
[node name="FishSales" type="VBoxContainer" parent="ShopPanel/Margin/Layout/Body"]
|
||||
custom_minimum_size = Vector2(420, 0)
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
theme_override_constants/separation = 6
|
||||
|
||||
[node name="SalesTitle" type="Label" parent="ShopPanel/Margin/Layout/Body/FishSales"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
text = "sell individual cooler fish • full base value"
|
||||
theme_override_font_sizes/font_size = 26
|
||||
|
||||
[node name="SalesBody" type="HSplitContainer" parent="ShopPanel/Margin/Layout/Body/FishSales"]
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
split_offset = 220
|
||||
theme_override_constants/separation = 8
|
||||
|
||||
[node name="ListPanel" type="PanelContainer" parent="ShopPanel/Margin/Layout/Body/FishSales/SalesBody"]
|
||||
custom_minimum_size = Vector2(205, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="ListMargin" type="MarginContainer" parent="ShopPanel/Margin/Layout/Body/FishSales/SalesBody/ListPanel"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/margin_left = 7
|
||||
theme_override_constants/margin_top = 7
|
||||
theme_override_constants/margin_right = 7
|
||||
theme_override_constants/margin_bottom = 7
|
||||
|
||||
[node name="ListStack" type="VBoxContainer" parent="ShopPanel/Margin/Layout/Body/FishSales/SalesBody/ListPanel/ListMargin"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="FishEmpty" type="Label" parent="ShopPanel/Margin/Layout/Body/FishSales/SalesBody/ListPanel/ListMargin/ListStack"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
text = "your cooler is empty."
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="FishList" type="ItemList" parent="ShopPanel/Margin/Layout/Body/FishSales/SalesBody/ListPanel/ListMargin/ListStack"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
fixed_icon_size = Vector2i(48, 36)
|
||||
icon_mode = 1
|
||||
select_mode = 1
|
||||
same_column_width = true
|
||||
|
||||
[node name="FishDetail" type="PanelContainer" parent="ShopPanel/Margin/Layout/Body/FishSales/SalesBody"]
|
||||
custom_minimum_size = Vector2(185, 0)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="DetailMargin" type="MarginContainer" parent="ShopPanel/Margin/Layout/Body/FishSales/SalesBody/FishDetail"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/margin_left = 9
|
||||
theme_override_constants/margin_top = 9
|
||||
theme_override_constants/margin_right = 9
|
||||
theme_override_constants/margin_bottom = 9
|
||||
|
||||
[node name="DetailStack" type="VBoxContainer" parent="ShopPanel/Margin/Layout/Body/FishSales/SalesBody/FishDetail/DetailMargin"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 6
|
||||
|
||||
[node name="FishTexture" type="TextureRect" parent="ShopPanel/Margin/Layout/Body/FishSales/SalesBody/FishDetail/DetailMargin/DetailStack"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(160, 90)
|
||||
layout_mode = 2
|
||||
expand_mode = 1
|
||||
stretch_mode = 5
|
||||
texture_filter = 1
|
||||
|
||||
[node name="FishName" type="Label" parent="ShopPanel/Margin/Layout/Body/FishSales/SalesBody/FishDetail/DetailMargin/DetailStack"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
text = "select a fish"
|
||||
horizontal_alignment = 1
|
||||
theme_override_font_sizes/font_size = 29
|
||||
|
||||
[node name="FishDetails" type="Label" parent="ShopPanel/Margin/Layout/Body/FishSales/SalesBody/FishDetail/DetailMargin/DetailStack"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
text = "choose one individual fish from your cooler."
|
||||
horizontal_alignment = 1
|
||||
autowrap_mode = 2
|
||||
|
||||
[node name="SelectionSummary" type="Label" parent="ShopPanel/Margin/Layout/Body/FishSales/SalesBody/FishDetail/DetailMargin/DetailStack"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
text = "no fish selected"
|
||||
horizontal_alignment = 1
|
||||
autowrap_mode = 2
|
||||
theme_override_colors/font_color = Color(0.208, 0.725, 0.78, 1)
|
||||
|
||||
[node name="SellButton" type="Button" parent="ShopPanel/Margin/Layout/Body/FishSales/SalesBody/FishDetail/DetailMargin/DetailStack"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
disabled = true
|
||||
text = "sell selected"
|
||||
|
||||
[node name="Upgrades" type="VBoxContainer" parent="ShopPanel/Margin/Layout/Body"]
|
||||
custom_minimum_size = Vector2(270, 0)
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
theme_override_constants/separation = 8
|
||||
|
||||
[node name="UpgradeTitle" type="Label" parent="ShopPanel/Margin/Layout/Body/Upgrades"]
|
||||
layout_mode = 2
|
||||
text = "fishing upgrades"
|
||||
theme_override_font_sizes/font_size = 26
|
||||
theme_override_font_sizes/font_size = 23
|
||||
|
||||
[node name="Supplies" type="VBoxContainer" parent="ShopPanel/Margin/Layout/Body"]
|
||||
custom_minimum_size = Vector2(210, 0)
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
theme_override_constants/separation = 6
|
||||
|
||||
[node name="Title" type="Label" parent="ShopPanel/Margin/Layout/Body/Supplies"]
|
||||
layout_mode = 2
|
||||
text = "supplies"
|
||||
theme_override_font_sizes/font_size = 26
|
||||
theme_override_font_sizes/font_size = 23
|
||||
|
||||
[node name="Scroll" type="ScrollContainer" parent="ShopPanel/Margin/Layout/Body/Supplies"]
|
||||
layout_mode = 2
|
||||
|
|
@ -233,16 +187,16 @@ layout_mode = 2
|
|||
[node name="Margin" type="MarginContainer" parent="ShopPanel/Margin/Layout/Body/Upgrades/ReelCard"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/margin_left = 9
|
||||
theme_override_constants/margin_top = 9
|
||||
theme_override_constants/margin_top = 7
|
||||
theme_override_constants/margin_right = 9
|
||||
theme_override_constants/margin_bottom = 9
|
||||
theme_override_constants/margin_bottom = 7
|
||||
|
||||
[node name="Row" type="HBoxContainer" parent="ShopPanel/Margin/Layout/Body/Upgrades/ReelCard/Margin"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 9
|
||||
|
||||
[node name="Icon" type="TextureRect" parent="ShopPanel/Margin/Layout/Body/Upgrades/ReelCard/Margin/Row"]
|
||||
custom_minimum_size = Vector2(48, 48)
|
||||
custom_minimum_size = Vector2(44, 44)
|
||||
layout_mode = 2
|
||||
texture = ExtResource("3_reel")
|
||||
expand_mode = 1
|
||||
|
|
@ -256,22 +210,25 @@ size_flags_horizontal = 3
|
|||
[node name="Name" type="Label" parent="ShopPanel/Margin/Layout/Body/Upgrades/ReelCard/Margin/Row/Data"]
|
||||
layout_mode = 2
|
||||
text = "reel speed"
|
||||
theme_override_font_sizes/font_size = 26
|
||||
theme_override_font_sizes/font_size = 22
|
||||
|
||||
[node name="ReelLevel" type="Label" parent="ShopPanel/Margin/Layout/Body/Upgrades/ReelCard/Margin/Row/Data"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
text = "level 0"
|
||||
theme_override_font_sizes/font_size = 18
|
||||
|
||||
[node name="ReelEffect" type="Label" parent="ShopPanel/Margin/Layout/Body/Upgrades/ReelCard/Margin/Row/Data"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
text = "1.00× → 1.10×"
|
||||
theme_override_font_sizes/font_size = 18
|
||||
|
||||
[node name="ReelCost" type="Label" parent="ShopPanel/Margin/Layout/Body/Upgrades/ReelCard/Margin/Row/Data"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
text = "$50"
|
||||
theme_override_font_sizes/font_size = 18
|
||||
|
||||
[node name="ReelPurchase" type="Button" parent="ShopPanel/Margin/Layout/Body/Upgrades/ReelCard/Margin/Row"]
|
||||
unique_name_in_owner = true
|
||||
|
|
@ -284,16 +241,16 @@ layout_mode = 2
|
|||
[node name="Margin" type="MarginContainer" parent="ShopPanel/Margin/Layout/Body/Upgrades/BarrierCard"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/margin_left = 9
|
||||
theme_override_constants/margin_top = 9
|
||||
theme_override_constants/margin_top = 7
|
||||
theme_override_constants/margin_right = 9
|
||||
theme_override_constants/margin_bottom = 9
|
||||
theme_override_constants/margin_bottom = 7
|
||||
|
||||
[node name="Row" type="HBoxContainer" parent="ShopPanel/Margin/Layout/Body/Upgrades/BarrierCard/Margin"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 9
|
||||
|
||||
[node name="Icon" type="TextureRect" parent="ShopPanel/Margin/Layout/Body/Upgrades/BarrierCard/Margin/Row"]
|
||||
custom_minimum_size = Vector2(48, 48)
|
||||
custom_minimum_size = Vector2(44, 44)
|
||||
layout_mode = 2
|
||||
texture = ExtResource("4_barrier")
|
||||
expand_mode = 1
|
||||
|
|
@ -307,22 +264,25 @@ size_flags_horizontal = 3
|
|||
[node name="Name" type="Label" parent="ShopPanel/Margin/Layout/Body/Upgrades/BarrierCard/Margin/Row/Data"]
|
||||
layout_mode = 2
|
||||
text = "barrier power"
|
||||
theme_override_font_sizes/font_size = 26
|
||||
theme_override_font_sizes/font_size = 22
|
||||
|
||||
[node name="BarrierLevel" type="Label" parent="ShopPanel/Margin/Layout/Body/Upgrades/BarrierCard/Margin/Row/Data"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
text = "level 0"
|
||||
theme_override_font_sizes/font_size = 18
|
||||
|
||||
[node name="BarrierEffect" type="Label" parent="ShopPanel/Margin/Layout/Body/Upgrades/BarrierCard/Margin/Row/Data"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
text = "1 damage → 2 damage"
|
||||
theme_override_font_sizes/font_size = 18
|
||||
|
||||
[node name="BarrierCost" type="Label" parent="ShopPanel/Margin/Layout/Body/Upgrades/BarrierCard/Margin/Row/Data"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
text = "$100"
|
||||
theme_override_font_sizes/font_size = 18
|
||||
|
||||
[node name="BarrierPurchase" type="Button" parent="ShopPanel/Margin/Layout/Body/Upgrades/BarrierCard/Margin/Row"]
|
||||
unique_name_in_owner = true
|
||||
|
|
@ -335,16 +295,16 @@ layout_mode = 2
|
|||
[node name="Margin" type="MarginContainer" parent="ShopPanel/Margin/Layout/Body/Upgrades/CoolerCard"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/margin_left = 9
|
||||
theme_override_constants/margin_top = 9
|
||||
theme_override_constants/margin_top = 7
|
||||
theme_override_constants/margin_right = 9
|
||||
theme_override_constants/margin_bottom = 9
|
||||
theme_override_constants/margin_bottom = 7
|
||||
|
||||
[node name="Row" type="HBoxContainer" parent="ShopPanel/Margin/Layout/Body/Upgrades/CoolerCard/Margin"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 9
|
||||
|
||||
[node name="Icon" type="TextureRect" parent="ShopPanel/Margin/Layout/Body/Upgrades/CoolerCard/Margin/Row"]
|
||||
custom_minimum_size = Vector2(48, 48)
|
||||
custom_minimum_size = Vector2(44, 44)
|
||||
layout_mode = 2
|
||||
texture = ExtResource("6_cooler")
|
||||
expand_mode = 1
|
||||
|
|
@ -358,74 +318,27 @@ size_flags_horizontal = 3
|
|||
[node name="Name" type="Label" parent="ShopPanel/Margin/Layout/Body/Upgrades/CoolerCard/Margin/Row/Data"]
|
||||
layout_mode = 2
|
||||
text = "cooler capacity"
|
||||
theme_override_font_sizes/font_size = 26
|
||||
theme_override_font_sizes/font_size = 22
|
||||
|
||||
[node name="CoolerLevel" type="Label" parent="ShopPanel/Margin/Layout/Body/Upgrades/CoolerCard/Margin/Row/Data"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
text = "level 0"
|
||||
theme_override_font_sizes/font_size = 18
|
||||
|
||||
[node name="CoolerEffect" type="Label" parent="ShopPanel/Margin/Layout/Body/Upgrades/CoolerCard/Margin/Row/Data"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
text = "12 → 18 fish"
|
||||
theme_override_font_sizes/font_size = 18
|
||||
|
||||
[node name="CoolerCost" type="Label" parent="ShopPanel/Margin/Layout/Body/Upgrades/CoolerCard/Margin/Row/Data"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
text = "$75"
|
||||
theme_override_font_sizes/font_size = 18
|
||||
|
||||
[node name="CoolerPurchase" type="Button" parent="ShopPanel/Margin/Layout/Body/Upgrades/CoolerCard/Margin/Row"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
text = "purchase"
|
||||
|
||||
[node name="SaleConfirmation" type="PanelContainer" parent="."]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
z_index = 10
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -320.0
|
||||
offset_top = -150.0
|
||||
offset_right = 320.0
|
||||
offset_bottom = 150.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
|
||||
[node name="Margin" type="MarginContainer" parent="SaleConfirmation"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/margin_left = 18
|
||||
theme_override_constants/margin_top = 16
|
||||
theme_override_constants/margin_right = 18
|
||||
theme_override_constants/margin_bottom = 16
|
||||
|
||||
[node name="Stack" type="VBoxContainer" parent="SaleConfirmation/Margin"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 12
|
||||
|
||||
[node name="ConfirmationText" type="Label" parent="SaleConfirmation/Margin/Stack"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
autowrap_mode = 2
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="Buttons" type="HBoxContainer" parent="SaleConfirmation/Margin/Stack"]
|
||||
layout_mode = 2
|
||||
alignment = 1
|
||||
theme_override_constants/separation = 8
|
||||
|
||||
[node name="ConfirmSale" type="Button" parent="SaleConfirmation/Margin/Stack/Buttons"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
text = "sell fish"
|
||||
theme_type_variation = &"DangerButton"
|
||||
|
||||
[node name="CancelSale" type="Button" parent="SaleConfirmation/Margin/Stack/Buttons"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
text = "cancel"
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ signal crisp_reset_focus_requested
|
|||
signal interactive_pointer_ui_changed(is_open: bool)
|
||||
signal passive_pointer_ui_changed(is_enabled: bool)
|
||||
signal player_menu_backdrop_visibility_changed(is_visible: bool)
|
||||
signal shop_backdrop_visibility_changed(is_visible: bool)
|
||||
|
||||
@onready var _status_label: Label = %StatusLabel
|
||||
@onready var _gameplay_transient_hud: Control = %GameplayTransientHUD
|
||||
|
|
@ -65,7 +66,7 @@ signal player_menu_backdrop_visibility_changed(is_visible: bool)
|
|||
$UIRoot/TitleScreen/ResponsiveTitleStage/TitlePresentationScaleRoot/SettingsPanel
|
||||
)
|
||||
@onready var _pause_settings_panel: SettingsPanelType = (
|
||||
$UIRoot/PauseMenu/ResponsivePauseStage/PausePresentationScaleRoot/SettingsCenter/SettingsPanel
|
||||
$UIRoot/CanonicalStage/PauseMenu/ResponsivePauseStage/PausePresentationScaleRoot/SettingsCenter/SettingsPanel
|
||||
)
|
||||
|
||||
var _showcase_active: bool = false
|
||||
|
|
@ -77,6 +78,8 @@ var _shop_open: bool = false
|
|||
var _chat_input_open: bool = false
|
||||
var _player_menu_hotbar_visible: bool = false
|
||||
var _item_effects: PlayerItemEffectsType
|
||||
var _main_shop_buyer: FishBuyerProfileType
|
||||
var _shop_interaction: ShopInteractionType
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
|
|
@ -151,6 +154,9 @@ func setup(
|
|||
_player_menu.inventory_hotbar_context_changed.connect(
|
||||
_on_inventory_hotbar_context_changed
|
||||
)
|
||||
_player_menu.shop_cooler_modal_changed.connect(
|
||||
_on_shop_cooler_modal_changed
|
||||
)
|
||||
_player_menu.setup(
|
||||
player,
|
||||
inventory,
|
||||
|
|
@ -174,9 +180,7 @@ func setup(
|
|||
_hotbar_ui.setup(hotbar, bag, item_catalog, fishing_spot)
|
||||
_fishing_shop.setup(
|
||||
player,
|
||||
inventory,
|
||||
wallet,
|
||||
sale_service,
|
||||
main_shop_buyer,
|
||||
fishing_upgrades,
|
||||
fishing_spot,
|
||||
|
|
@ -184,10 +188,18 @@ func setup(
|
|||
bag,
|
||||
item_catalog,
|
||||
cooler_capacity,
|
||||
network_session,
|
||||
network_shop_service
|
||||
network_shop_service,
|
||||
)
|
||||
_fishing_shop.menu_visibility_changed.connect(_on_shop_visibility_changed)
|
||||
_fishing_shop.sell_fish_requested.connect(_on_shop_sell_fish_requested)
|
||||
_fishing_shop.shop_cooler_return_requested.connect(
|
||||
_on_shop_cooler_return_requested
|
||||
)
|
||||
_fishing_shop.shop_cooler_confirmation_cancel_requested.connect(
|
||||
_player_menu.cancel_shop_cooler_confirmation
|
||||
)
|
||||
_main_shop_buyer = main_shop_buyer
|
||||
_shop_interaction = shop_interaction
|
||||
|
||||
|
||||
func setup_data_and_identity(
|
||||
|
|
@ -554,6 +566,9 @@ func _on_player_menu_exit_started() -> void:
|
|||
|
||||
func _on_shop_visibility_changed(is_open: bool) -> void:
|
||||
_shop_open = is_open
|
||||
shop_backdrop_visibility_changed.emit(is_open)
|
||||
if not is_open and _player_menu.is_shop_cooler_mounted():
|
||||
_player_menu.unmount_shop_cooler()
|
||||
_refresh_chat_availability()
|
||||
_refresh_hotbar_visibility()
|
||||
_hotbar_ui.set_gameplay_input_enabled(
|
||||
|
|
@ -567,6 +582,33 @@ func _on_shop_visibility_changed(is_open: bool) -> void:
|
|||
_emit_interactive_pointer_ui_changed()
|
||||
|
||||
|
||||
func _on_shop_sell_fish_requested() -> void:
|
||||
if (
|
||||
not _fishing_shop.visible
|
||||
or _main_shop_buyer == null
|
||||
or not _main_shop_buyer.is_valid()
|
||||
or _shop_interaction == null
|
||||
or not _shop_interaction.is_local_player_in_range()
|
||||
or _fishing_spot == null
|
||||
or not _fishing_spot.is_ready_for_shop_transaction()
|
||||
):
|
||||
return
|
||||
if _player_menu.mount_shop_cooler(
|
||||
_fishing_shop.get_shop_cooler_mount(),
|
||||
_main_shop_buyer,
|
||||
):
|
||||
_fishing_shop.activate_shop_cooler_page()
|
||||
|
||||
|
||||
func _on_shop_cooler_return_requested() -> void:
|
||||
_player_menu.unmount_shop_cooler()
|
||||
_fishing_shop.deactivate_shop_cooler_page()
|
||||
|
||||
|
||||
func _on_shop_cooler_modal_changed(is_open: bool) -> void:
|
||||
_fishing_shop.set_shop_cooler_modal_open(is_open)
|
||||
|
||||
|
||||
func _on_inventory_hotbar_context_changed(show_hotbar: bool) -> void:
|
||||
var context_changed: bool = _player_menu_hotbar_visible != show_hotbar
|
||||
_player_menu_hotbar_visible = show_hotbar
|
||||
|
|
|
|||
|
|
@ -41,7 +41,11 @@ script = ExtResource("1_ui")
|
|||
unique_name_in_owner = true
|
||||
mouse_filter = 2
|
||||
|
||||
[node name="GameplayTransientHUD" type="Control" parent="UIRoot"]
|
||||
[node name="CanonicalStage" type="Control" parent="UIRoot"]
|
||||
unique_name_in_owner = true
|
||||
mouse_filter = 2
|
||||
|
||||
[node name="GameplayTransientHUD" type="Control" parent="UIRoot/CanonicalStage"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
|
|
@ -51,7 +55,7 @@ grow_horizontal = 2
|
|||
grow_vertical = 2
|
||||
mouse_filter = 2
|
||||
|
||||
[node name="FishingPanel" type="PanelContainer" parent="UIRoot/GameplayTransientHUD"]
|
||||
[node name="FishingPanel" type="PanelContainer" parent="UIRoot/CanonicalStage/GameplayTransientHUD"]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
z_index = 60
|
||||
|
|
@ -69,33 +73,33 @@ grow_vertical = 0
|
|||
mouse_filter = 2
|
||||
theme = ExtResource("3_theme")
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="UIRoot/GameplayTransientHUD/FishingPanel"]
|
||||
[node name="MarginContainer" type="MarginContainer" parent="UIRoot/CanonicalStage/GameplayTransientHUD/FishingPanel"]
|
||||
theme_override_constants/margin_left = 14
|
||||
theme_override_constants/margin_top = 8
|
||||
theme_override_constants/margin_right = 14
|
||||
theme_override_constants/margin_bottom = 8
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="UIRoot/GameplayTransientHUD/FishingPanel/MarginContainer"]
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="UIRoot/CanonicalStage/GameplayTransientHUD/FishingPanel/MarginContainer"]
|
||||
theme_override_constants/separation = 4
|
||||
|
||||
[node name="StatusLabel" type="Label" parent="UIRoot/GameplayTransientHUD/FishingPanel/MarginContainer/VBoxContainer"]
|
||||
[node name="StatusLabel" type="Label" parent="UIRoot/CanonicalStage/GameplayTransientHUD/FishingPanel/MarginContainer/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
text = ""
|
||||
horizontal_alignment = 1
|
||||
theme_override_font_sizes/font_size = 16
|
||||
|
||||
[node name="ShowcaseDetails" type="Label" parent="UIRoot/GameplayTransientHUD/FishingPanel/MarginContainer/VBoxContainer"]
|
||||
[node name="ShowcaseDetails" type="Label" parent="UIRoot/CanonicalStage/GameplayTransientHUD/FishingPanel/MarginContainer/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="CatchTrack" type="Control" parent="UIRoot/GameplayTransientHUD/FishingPanel/MarginContainer/VBoxContainer"]
|
||||
[node name="CatchTrack" type="Control" parent="UIRoot/CanonicalStage/GameplayTransientHUD/FishingPanel/MarginContainer/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
custom_minimum_size = Vector2(0, 20)
|
||||
|
||||
[node name="GreenCatchProgress" type="ProgressBar" parent="UIRoot/GameplayTransientHUD/FishingPanel/MarginContainer/VBoxContainer/CatchTrack"]
|
||||
[node name="GreenCatchProgress" type="ProgressBar" parent="UIRoot/CanonicalStage/GameplayTransientHUD/FishingPanel/MarginContainer/VBoxContainer/CatchTrack"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
|
|
@ -109,7 +113,7 @@ theme_override_styles/fill = SubResource("StyleBox_catch_fill")
|
|||
value = 0.0
|
||||
show_percentage = false
|
||||
|
||||
[node name="RedChaseProgress" type="ProgressBar" parent="UIRoot/GameplayTransientHUD/FishingPanel/MarginContainer/VBoxContainer/CatchTrack"]
|
||||
[node name="RedChaseProgress" type="ProgressBar" parent="UIRoot/CanonicalStage/GameplayTransientHUD/FishingPanel/MarginContainer/VBoxContainer/CatchTrack"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
|
|
@ -123,7 +127,7 @@ theme_override_styles/fill = SubResource("StyleBox_chase_fill")
|
|||
value = 0.0
|
||||
show_percentage = false
|
||||
|
||||
[node name="BarrierMarkers" type="Control" parent="UIRoot/GameplayTransientHUD/FishingPanel/MarginContainer/VBoxContainer/CatchTrack"]
|
||||
[node name="BarrierMarkers" type="Control" parent="UIRoot/CanonicalStage/GameplayTransientHUD/FishingPanel/MarginContainer/VBoxContainer/CatchTrack"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
|
|
@ -133,23 +137,23 @@ grow_horizontal = 2
|
|||
grow_vertical = 2
|
||||
mouse_filter = 2
|
||||
|
||||
[node name="BarrierSummary" type="Label" parent="UIRoot/GameplayTransientHUD/FishingPanel/MarginContainer/VBoxContainer"]
|
||||
[node name="BarrierSummary" type="Label" parent="UIRoot/CanonicalStage/GameplayTransientHUD/FishingPanel/MarginContainer/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="BarrierHealth" type="Label" parent="UIRoot/GameplayTransientHUD/FishingPanel/MarginContainer/VBoxContainer"]
|
||||
[node name="BarrierHealth" type="Label" parent="UIRoot/CanonicalStage/GameplayTransientHUD/FishingPanel/MarginContainer/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="PlayerMenu" parent="UIRoot" instance=ExtResource("2_menu")]
|
||||
[node name="PlayerMenu" parent="UIRoot/CanonicalStage" instance=ExtResource("2_menu")]
|
||||
unique_name_in_owner = true
|
||||
|
||||
[node name="Hotbar" parent="UIRoot" instance=ExtResource("7_hotbar")]
|
||||
[node name="Hotbar" parent="UIRoot/CanonicalStage" instance=ExtResource("7_hotbar")]
|
||||
unique_name_in_owner = true
|
||||
|
||||
[node name="ShopPrompt" type="PanelContainer" parent="UIRoot/GameplayTransientHUD"]
|
||||
[node name="ShopPrompt" type="PanelContainer" parent="UIRoot/CanonicalStage/GameplayTransientHUD"]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
z_index = 55
|
||||
|
|
@ -167,22 +171,22 @@ grow_vertical = 0
|
|||
mouse_filter = 2
|
||||
theme = ExtResource("3_theme")
|
||||
|
||||
[node name="Margin" type="MarginContainer" parent="UIRoot/GameplayTransientHUD/ShopPrompt"]
|
||||
[node name="Margin" type="MarginContainer" parent="UIRoot/CanonicalStage/GameplayTransientHUD/ShopPrompt"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/margin_left = 12
|
||||
theme_override_constants/margin_top = 7
|
||||
theme_override_constants/margin_right = 12
|
||||
theme_override_constants/margin_bottom = 7
|
||||
|
||||
[node name="Label" type="Label" parent="UIRoot/GameplayTransientHUD/ShopPrompt/Margin"]
|
||||
[node name="Label" type="Label" parent="UIRoot/CanonicalStage/GameplayTransientHUD/ShopPrompt/Margin"]
|
||||
layout_mode = 2
|
||||
text = "press e to open fishing shop"
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="FishingShop" parent="UIRoot" instance=ExtResource("8_shop")]
|
||||
[node name="FishingShop" parent="UIRoot/CanonicalStage" instance=ExtResource("8_shop")]
|
||||
unique_name_in_owner = true
|
||||
|
||||
[node name="EffectStatus" type="Label" parent="UIRoot/GameplayTransientHUD"]
|
||||
[node name="EffectStatus" type="Label" parent="UIRoot/CanonicalStage/GameplayTransientHUD"]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
z_index = 54
|
||||
|
|
@ -223,5 +227,5 @@ script = ExtResource("4_fade")
|
|||
[node name="TitleScreen" parent="UIRoot" instance=ExtResource("5_title")]
|
||||
unique_name_in_owner = true
|
||||
|
||||
[node name="PauseMenu" parent="UIRoot" instance=ExtResource("6_pause")]
|
||||
[node name="PauseMenu" parent="UIRoot/CanonicalStage" instance=ExtResource("6_pause")]
|
||||
unique_name_in_owner = true
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ const PAUSE_DESKTOP_REFERENCE_SIZE: Vector2 = Vector2(1280.0, 720.0)
|
|||
const PAUSE_COMPACT_REFERENCE_SIZE: Vector2 = Vector2(640.0, 480.0)
|
||||
const COMPACT_HEIGHT_THRESHOLD: float = 560.0
|
||||
const VISIBILITY_FADE_DURATION: float = 0.55
|
||||
const BACKDROP_TARGET_ALPHA: float = 0.68
|
||||
const PlayerType = preload("res://player/player.gd")
|
||||
const SaveManagerType = preload("res://save/player_save_manager.gd")
|
||||
const SettingsManagerType = preload(
|
||||
|
|
@ -48,7 +47,6 @@ enum CloseReason {
|
|||
@onready var _presentation_scale_root: Control = %PausePresentationScaleRoot
|
||||
@onready var _root_page: SettingsBubblePage = %RootPage
|
||||
@onready var _settings_panel: SettingsPanelType = %SettingsPanel
|
||||
@onready var _dim_background: ColorRect = %DimBackground
|
||||
@onready var _transition_flurry: BubbleTransitionFlurry = (
|
||||
%TransitionBubbleLayer
|
||||
)
|
||||
|
|
@ -75,8 +73,6 @@ var _action_in_progress: bool = false
|
|||
var _root_transition_active: bool = false
|
||||
var _root_transition_generation: int = 0
|
||||
var _closing_menu: bool = false
|
||||
var _backdrop_fade: Tween
|
||||
var _backdrop_fade_generation: int = 0
|
||||
var _pending_join_endpoint: String = ""
|
||||
|
||||
|
||||
|
|
@ -98,7 +94,6 @@ func _ready() -> void:
|
|||
)
|
||||
_join_game_page.join_requested.connect(_on_join_game_requested)
|
||||
_join_game_page.back_requested.connect(_close_join_game)
|
||||
_dim_background.color.a = 0.0
|
||||
_confirmation_page.hide_page()
|
||||
resized.connect(_update_responsive_pause_stage)
|
||||
call_deferred("_update_responsive_pause_stage")
|
||||
|
|
@ -144,7 +139,6 @@ func open_menu() -> void:
|
|||
_action_in_progress = false
|
||||
_root_page.hide_page()
|
||||
show()
|
||||
_fade_backdrop(true)
|
||||
_update_responsive_pause_stage()
|
||||
_begin_root_entry(false)
|
||||
menu_visibility_changed.emit(true)
|
||||
|
|
@ -159,7 +153,6 @@ func resume() -> void:
|
|||
or _confirmation_action != ConfirmationAction.NONE
|
||||
):
|
||||
return
|
||||
_fade_backdrop(false)
|
||||
_begin_root_exit(_finish_user_close)
|
||||
|
||||
|
||||
|
|
@ -268,7 +261,6 @@ func _finish_open_settings() -> void:
|
|||
_settings_panel.open_panel(
|
||||
_settings_manager,
|
||||
SettingsPanelType.PresentationMode.GAMEPLAY_MODAL,
|
||||
true,
|
||||
true
|
||||
)
|
||||
|
||||
|
|
@ -493,9 +485,6 @@ func _finish_close(reason: CloseReason, restore_controls: bool) -> void:
|
|||
_closing_menu = false
|
||||
_root_transition_generation += 1
|
||||
_root_transition_active = false
|
||||
_cancel_backdrop_fade()
|
||||
_dim_background.color.a = 0.0
|
||||
_dim_background.hide()
|
||||
_settings_panel.hide()
|
||||
_join_game_page.close_page()
|
||||
_root_page.hide_page()
|
||||
|
|
@ -519,45 +508,6 @@ func _emit_transition_flurry() -> void:
|
|||
_transition_flurry.emit_flurry()
|
||||
|
||||
|
||||
func _fade_backdrop(fade_in: bool) -> void:
|
||||
_backdrop_fade_generation += 1
|
||||
_cancel_backdrop_fade()
|
||||
_dim_background.show()
|
||||
var target_alpha: float = BACKDROP_TARGET_ALPHA if fade_in else 0.0
|
||||
if is_equal_approx(_dim_background.color.a, target_alpha):
|
||||
_finish_backdrop_fade(_backdrop_fade_generation, fade_in)
|
||||
return
|
||||
var generation: int = _backdrop_fade_generation
|
||||
_backdrop_fade = create_tween()
|
||||
_backdrop_fade.tween_property(
|
||||
_dim_background,
|
||||
"color:a",
|
||||
target_alpha,
|
||||
VISIBILITY_FADE_DURATION
|
||||
).set_trans(Tween.TRANS_CUBIC).set_ease(Tween.EASE_IN_OUT)
|
||||
_backdrop_fade.finished.connect(
|
||||
_finish_backdrop_fade.bind(generation, fade_in),
|
||||
CONNECT_ONE_SHOT
|
||||
)
|
||||
|
||||
|
||||
func _finish_backdrop_fade(generation: int, faded_in: bool) -> void:
|
||||
if generation != _backdrop_fade_generation:
|
||||
return
|
||||
_backdrop_fade = null
|
||||
_dim_background.color.a = (
|
||||
BACKDROP_TARGET_ALPHA if faded_in else 0.0
|
||||
)
|
||||
if not faded_in:
|
||||
_dim_background.hide()
|
||||
|
||||
|
||||
func _cancel_backdrop_fade() -> void:
|
||||
if _backdrop_fade != null:
|
||||
_backdrop_fade.kill()
|
||||
_backdrop_fade = null
|
||||
|
||||
|
||||
func _update_responsive_pause_stage() -> void:
|
||||
if not is_node_ready():
|
||||
return
|
||||
|
|
|
|||
|
|
@ -25,17 +25,6 @@ mouse_filter = 0
|
|||
theme = ExtResource("3_theme")
|
||||
script = ExtResource("1_script")
|
||||
|
||||
[node name="DimBackground" type="ColorRect" 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 = 0
|
||||
color = Color(0.025, 0.12, 0.19, 0.68)
|
||||
|
||||
[node name="TransitionBubbleLayer" type="Control" parent="."]
|
||||
unique_name_in_owner = true
|
||||
z_index = 1
|
||||
|
|
|
|||
|
|
@ -79,10 +79,12 @@ const COOLER_RARITY_UNCOMMON := Color("64c87c")
|
|||
const COOLER_RARITY_RARE := Color("6098dd")
|
||||
const COOLER_RARITY_EPIC := Color("a979cf")
|
||||
const COOLER_RARITY_LEGENDARY := Color("db78a7")
|
||||
const MAIN_SHOP_BUYER_ID: StringName = &"main_fishing_shop"
|
||||
|
||||
signal menu_visibility_changed(is_open: bool)
|
||||
signal inventory_hotbar_context_changed(show_hotbar: bool)
|
||||
signal menu_exit_started
|
||||
signal shop_cooler_modal_changed(is_open: bool)
|
||||
|
||||
enum Section {
|
||||
COOLER,
|
||||
|
|
@ -131,6 +133,7 @@ const INVENTORY_HEADER_INSET := Vector2(24.0, 20.0)
|
|||
const INVENTORY_HEADER_HEIGHT := 40.0
|
||||
const INVENTORY_MAIN_CORNER_RADIUS: int = 58
|
||||
const INVENTORY_INNER_CORNER_RADIUS: int = 45
|
||||
const SALE_CONFIRMATION_SIZE := Vector2(520.0, 190.0)
|
||||
|
||||
@onready var _navigation_cluster: BubbleClusterType = %NavigationCluster
|
||||
@onready var _presentation_scale_root: Control = %PlayerMenuPresentationScaleRoot
|
||||
|
|
@ -276,6 +279,12 @@ var _reservations: PlayerAssetReservationService
|
|||
var _network_profile_service: NetworkProfileService
|
||||
var _network_player_list: NetworkPlayerListService
|
||||
var _default_buyer: FishBuyerProfileType
|
||||
var _sale_buyer_override: FishBuyerProfileType
|
||||
var _shop_cooler_context_active: bool = false
|
||||
var _cooler_original_parent: Node
|
||||
var _cooler_original_index: int = -1
|
||||
var _confirmation_original_parent: Node
|
||||
var _confirmation_original_index: int = -1
|
||||
var _catalog: FishPoolType
|
||||
var _fishing_spot: FishingSpotType
|
||||
var _bag: PlayerBagType
|
||||
|
|
@ -336,6 +345,10 @@ var _logbook_page_tween: Tween
|
|||
|
||||
func _ready() -> void:
|
||||
_configure_inventory_transition_group()
|
||||
_cooler_original_parent = _cooler_page.get_parent()
|
||||
_cooler_original_index = _cooler_page.get_index()
|
||||
_confirmation_original_parent = _sale_confirmation.get_parent()
|
||||
_confirmation_original_index = _sale_confirmation.get_index()
|
||||
_inventory_sub_tabs.move_child(_tackle_sub_tab, 1)
|
||||
_inventory_sub_tabs.move_child(_bag_sub_tab, 2)
|
||||
_inventory_tab.pressed.connect(_show_last_inventory_section)
|
||||
|
|
@ -652,6 +665,7 @@ func consume_escape() -> bool:
|
|||
func open_menu() -> void:
|
||||
if (
|
||||
visible
|
||||
or _shop_cooler_context_active
|
||||
or _player == null
|
||||
or _fishing_spot == null
|
||||
or not _fishing_spot.can_open_player_menu()
|
||||
|
|
@ -678,6 +692,99 @@ func open_menu() -> void:
|
|||
menu_visibility_changed.emit(true)
|
||||
|
||||
|
||||
func mount_shop_cooler(
|
||||
host: Control,
|
||||
buyer: FishBuyerProfileType,
|
||||
) -> bool:
|
||||
if (
|
||||
visible
|
||||
or _shop_cooler_context_active
|
||||
or host == null
|
||||
or not is_instance_valid(host)
|
||||
or buyer == null
|
||||
or not buyer.is_valid()
|
||||
or buyer.id != MAIN_SHOP_BUYER_ID
|
||||
):
|
||||
return false
|
||||
_menu_generation += 1
|
||||
_cancel_page_tween()
|
||||
_transitioning = false
|
||||
_page_transitioning = false
|
||||
_sale_buyer_override = buyer
|
||||
_shop_cooler_context_active = true
|
||||
_current_section = Section.COOLER
|
||||
_last_inventory_section = Section.COOLER
|
||||
_cooler_page.reparent(host, false)
|
||||
_sale_confirmation.reparent(host, false)
|
||||
_cooler_page.position = Vector2.ZERO
|
||||
_cooler_page.size = DESKTOP_REFERENCE_SIZE
|
||||
_cooler_page.scale = Vector2.ONE
|
||||
_cooler_page.modulate = Color.WHITE
|
||||
_cooler_page.visible = true
|
||||
_sale_confirmation.visible = false
|
||||
_update_shell_layout()
|
||||
_refresh_inventory()
|
||||
_set_content_interactive(true)
|
||||
_update_cooler_water_mask()
|
||||
set_process(true)
|
||||
call_deferred("_focus_shop_cooler")
|
||||
return true
|
||||
|
||||
|
||||
func unmount_shop_cooler() -> void:
|
||||
if not _shop_cooler_context_active:
|
||||
return
|
||||
_close_sale_confirmation()
|
||||
_set_content_interactive(false)
|
||||
_cooler_page.visible = false
|
||||
_cooler_page.reparent(_cooler_original_parent, false)
|
||||
_cooler_original_parent.move_child(
|
||||
_cooler_page,
|
||||
mini(_cooler_original_index, _cooler_original_parent.get_child_count() - 1),
|
||||
)
|
||||
_sale_confirmation.reparent(_confirmation_original_parent, false)
|
||||
_confirmation_original_parent.move_child(
|
||||
_sale_confirmation,
|
||||
mini(
|
||||
_confirmation_original_index,
|
||||
_confirmation_original_parent.get_child_count() - 1,
|
||||
),
|
||||
)
|
||||
_sale_buyer_override = null
|
||||
_shop_cooler_context_active = false
|
||||
_menu_generation += 1
|
||||
if not visible:
|
||||
set_process(false)
|
||||
|
||||
|
||||
func is_shop_cooler_mounted() -> bool:
|
||||
return _shop_cooler_context_active
|
||||
|
||||
|
||||
func cancel_shop_cooler_confirmation() -> void:
|
||||
if _shop_cooler_context_active and _sale_confirmation.visible:
|
||||
_close_sale_confirmation()
|
||||
|
||||
|
||||
func _focus_shop_cooler() -> void:
|
||||
if not _shop_cooler_context_active or not _cooler_page.is_visible_in_tree():
|
||||
return
|
||||
var focused_node := _fish_nodes.get(
|
||||
_fish_selection.get_focused_id()
|
||||
) as CoolerFishSpriteType
|
||||
if focused_node != null and focused_node.focus_mode != Control.FOCUS_NONE:
|
||||
focused_node.grab_focus()
|
||||
return
|
||||
for fish_catch: FishCatchType in _sorted_catches:
|
||||
var fish_node := _fish_nodes.get(
|
||||
fish_catch.catch_id
|
||||
) as CoolerFishSpriteType
|
||||
if fish_node != null and fish_node.focus_mode != Control.FOCUS_NONE:
|
||||
fish_node.grab_focus()
|
||||
return
|
||||
_cooler_sort_option.grab_focus()
|
||||
|
||||
|
||||
func close_menu(
|
||||
reason: CloseReason = CloseReason.USER,
|
||||
restore_controls: bool = true,
|
||||
|
|
@ -886,6 +993,9 @@ func _show_last_inventory_section() -> void:
|
|||
|
||||
|
||||
func _focus_current_section() -> void:
|
||||
if _shop_cooler_context_active:
|
||||
_focus_shop_cooler()
|
||||
return
|
||||
if _current_section == Section.COOLER:
|
||||
_cooler_sub_tab.grab_focus()
|
||||
elif _current_section == Section.BAG:
|
||||
|
|
@ -903,12 +1013,15 @@ func _focus_current_section() -> void:
|
|||
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
if visible:
|
||||
if visible or _shop_cooler_context_active:
|
||||
_motion_elapsed += delta
|
||||
_navigation_cluster.advance_motion(delta)
|
||||
_apply_navigation_selection_presentation()
|
||||
if visible:
|
||||
_navigation_cluster.advance_motion(delta)
|
||||
_apply_navigation_selection_presentation()
|
||||
for fish_node: CoolerFishSpriteType in _fish_nodes.values():
|
||||
fish_node.advance_presentation(delta, _motion_elapsed)
|
||||
if not visible:
|
||||
return
|
||||
var bag_motion_enabled: bool = (
|
||||
not _bag_drag_active and not get_viewport().gui_is_dragging()
|
||||
)
|
||||
|
|
@ -1040,6 +1153,20 @@ func _apply_inventory_styles() -> void:
|
|||
"font_color",
|
||||
UtilityPageStyle.OCEAN_TEXT_PRIMARY,
|
||||
)
|
||||
_sale_confirmation.add_theme_stylebox_override(
|
||||
"panel",
|
||||
UtilityPageStyle.panel_style(),
|
||||
)
|
||||
_confirmation_message.add_theme_font_override(
|
||||
"font",
|
||||
UtilityPageStyle.TuffyFont,
|
||||
)
|
||||
_confirmation_message.add_theme_color_override(
|
||||
"font_color",
|
||||
UtilityPageStyle.OCEAN_TEXT_PRIMARY,
|
||||
)
|
||||
UtilityPageStyle.apply_ocean_button(_confirm_sale_button)
|
||||
UtilityPageStyle.apply_ocean_button(_cancel_sale_button)
|
||||
|
||||
|
||||
func _set_bag_view(view: BagView) -> void:
|
||||
|
|
@ -1531,11 +1658,9 @@ func _update_shell_layout() -> void:
|
|||
_players_page.set_anchors_preset(Control.PRESET_TOP_LEFT)
|
||||
_players_page.position = Vector2.ZERO
|
||||
_players_page.size = reference_size
|
||||
_sale_confirmation.size = SALE_CONFIRMATION_SIZE
|
||||
_sale_confirmation.position = (
|
||||
Vector2(70.0, 128.0) if compact else Vector2(320.0, 200.0)
|
||||
)
|
||||
_sale_confirmation.size = (
|
||||
Vector2(500.0, 250.0) if compact else Vector2(640.0, 320.0)
|
||||
(reference_size - SALE_CONFIRMATION_SIZE) * 0.5
|
||||
)
|
||||
_cooler_host.custom_minimum_size = Vector2(
|
||||
520.0 if compact else 800.0,
|
||||
|
|
@ -2592,11 +2717,18 @@ func _configure_cooler_fish_focus() -> void:
|
|||
controls.append(fish_node)
|
||||
var columns: int = 3 if _compact_layout else 9
|
||||
if controls.is_empty():
|
||||
_cooler_sub_tab.focus_neighbor_bottom = NodePath()
|
||||
if not _shop_cooler_context_active:
|
||||
_cooler_sub_tab.focus_neighbor_bottom = NodePath()
|
||||
return
|
||||
_cooler_sub_tab.focus_neighbor_bottom = _cooler_sub_tab.get_path_to(
|
||||
controls.front()
|
||||
var top_control: Control = (
|
||||
_cooler_sort_option
|
||||
if _shop_cooler_context_active
|
||||
else _cooler_sub_tab
|
||||
)
|
||||
if not _shop_cooler_context_active:
|
||||
_cooler_sub_tab.focus_neighbor_bottom = _cooler_sub_tab.get_path_to(
|
||||
controls.front()
|
||||
)
|
||||
for index: int in controls.size():
|
||||
var control: CoolerFishSpriteType = controls[index]
|
||||
control.focus_neighbor_left = control.get_path_to(
|
||||
|
|
@ -2606,7 +2738,7 @@ func _configure_cooler_fish_focus() -> void:
|
|||
controls[mini(index + 1, controls.size() - 1)]
|
||||
)
|
||||
control.focus_neighbor_top = (
|
||||
control.get_path_to(_cooler_sub_tab)
|
||||
control.get_path_to(top_control)
|
||||
if index < columns
|
||||
else control.get_path_to(controls[index - columns])
|
||||
)
|
||||
|
|
@ -2776,9 +2908,10 @@ func _update_inventory_detail(fish_catch: FishCatchType) -> void:
|
|||
_cooler_detail_texture.texture = fish_catch.fish.display_texture
|
||||
_cooler_detail_texture.visible = fish_catch.fish.display_texture != null
|
||||
_cooler_detail_name.text = fish_catch.fish.display_name
|
||||
var active_buyer: FishBuyerProfileType = _get_active_sale_buyer()
|
||||
var individual_preview: FishSaleResultType = (
|
||||
_sale_service.preview_batch([fish_catch.catch_id], _default_buyer)
|
||||
if _sale_service != null
|
||||
_sale_service.preview_batch([fish_catch.catch_id], active_buyer)
|
||||
if _sale_service != null and active_buyer != null
|
||||
else null
|
||||
)
|
||||
var buyer_offer: int = (
|
||||
|
|
@ -2793,8 +2926,8 @@ func _update_inventory_detail(fish_catch: FishCatchType) -> void:
|
|||
):
|
||||
_cooler_detail_name.text += " • reserved in mail"
|
||||
_cooler_weight_unit.text = "lb • %s" % fish_catch.fish.get_rarity_name()
|
||||
if buyer_offer >= 0 and _default_buyer != null:
|
||||
_cooler_offer_label.text = "%s offer" % _default_buyer.display_name
|
||||
if buyer_offer >= 0 and active_buyer != null:
|
||||
_cooler_offer_label.text = _get_offer_label(active_buyer)
|
||||
_cooler_offer_value.text = "$%d" % buyer_offer
|
||||
else:
|
||||
_cooler_offer_label.text = "buyer unavailable"
|
||||
|
|
@ -2831,6 +2964,11 @@ func _update_inventory_detail(fish_catch: FishCatchType) -> void:
|
|||
|
||||
|
||||
func _update_sale_summary() -> void:
|
||||
var active_buyer: FishBuyerProfileType = _get_active_sale_buyer()
|
||||
var buyer_id: StringName = (
|
||||
active_buyer.id if active_buyer != null else StringName()
|
||||
)
|
||||
var offer_label: String = _get_offer_label(active_buyer)
|
||||
var selected_ids: Array[StringName] = _fish_selection.get_selected_ids()
|
||||
var selected_count: int = selected_ids.size()
|
||||
_sell_button.text = (
|
||||
|
|
@ -2842,7 +2980,7 @@ func _update_sale_summary() -> void:
|
|||
if selected_count == 0:
|
||||
_selection_summary.text = "no fish selected"
|
||||
_selection_status.set_content("selected", "none")
|
||||
_offer_status.set_content("pelican offer", "—")
|
||||
_offer_status.set_content(offer_label, "—")
|
||||
_sell_button.text = "sell fish"
|
||||
_sell_button.disabled = true
|
||||
_sell_bubble.disabled = true
|
||||
|
|
@ -2866,7 +3004,7 @@ func _update_sale_summary() -> void:
|
|||
else "%d fish selected" % selected_count
|
||||
)
|
||||
_selection_status.set_content("selected", str(selected_count))
|
||||
_offer_status.set_content("pelican offer", "pending")
|
||||
_offer_status.set_content(offer_label, "pending")
|
||||
_sell_button.disabled = true
|
||||
_sell_bubble.disabled = true
|
||||
_sale_unavailable.text = "Selling…"
|
||||
|
|
@ -2874,7 +3012,8 @@ func _update_sale_summary() -> void:
|
|||
return
|
||||
if (
|
||||
_network_sale_service == null
|
||||
or not _network_sale_service.can_request_sale()
|
||||
or buyer_id.is_empty()
|
||||
or not _network_sale_service.can_request_sale(buyer_id)
|
||||
):
|
||||
_selection_summary.text = (
|
||||
"1 fish selected"
|
||||
|
|
@ -2882,7 +3021,7 @@ func _update_sale_summary() -> void:
|
|||
else "%d fish selected" % selected_count
|
||||
)
|
||||
_selection_status.set_content("selected", str(selected_count))
|
||||
_offer_status.set_content("pelican offer", "unavailable")
|
||||
_offer_status.set_content(offer_label, "unavailable")
|
||||
_sell_button.disabled = true
|
||||
_sell_bubble.disabled = true
|
||||
_sell_bubble.persistent_mark = false
|
||||
|
|
@ -2893,8 +3032,8 @@ func _update_sale_summary() -> void:
|
|||
_sale_unavailable.visible = true
|
||||
return
|
||||
var preview: FishSaleResultType = (
|
||||
_sale_service.preview_batch(selected_ids, _default_buyer)
|
||||
if _sale_service != null
|
||||
_sale_service.preview_batch(selected_ids, active_buyer)
|
||||
if _sale_service != null and active_buyer != null
|
||||
else null
|
||||
)
|
||||
var count_text: String = (
|
||||
|
|
@ -2907,21 +3046,21 @@ func _update_sale_summary() -> void:
|
|||
if (
|
||||
preview != null
|
||||
and preview.payout >= 0
|
||||
and _default_buyer != null
|
||||
and active_buyer != null
|
||||
and (
|
||||
preview.is_success()
|
||||
or preview.status == FishSaleResultType.Status.FAVORITED
|
||||
)
|
||||
):
|
||||
_selection_summary.text += "\n%s total offer: $%d" % [
|
||||
_default_buyer.display_name,
|
||||
active_buyer.display_name,
|
||||
preview.payout,
|
||||
]
|
||||
_set_cooler_selection_summary(selected_count, preview.payout)
|
||||
_offer_status.set_content("pelican offer", "$%d" % preview.payout)
|
||||
_offer_status.set_content(offer_label, "$%d" % preview.payout)
|
||||
else:
|
||||
_set_cooler_selection_summary(selected_count, -1)
|
||||
_offer_status.set_content("pelican offer", "unavailable")
|
||||
_offer_status.set_content(offer_label, "unavailable")
|
||||
_sell_button.disabled = preview == null or not preview.is_success()
|
||||
_sell_bubble.disabled = _sell_button.disabled
|
||||
_sell_bubble.persistent_mark = false
|
||||
|
|
@ -2962,6 +3101,10 @@ func _on_favorite_pressed() -> void:
|
|||
|
||||
|
||||
func _on_sell_pressed() -> void:
|
||||
var active_buyer: FishBuyerProfileType = _get_active_sale_buyer()
|
||||
var buyer_id: StringName = (
|
||||
active_buyer.id if active_buyer != null else StringName()
|
||||
)
|
||||
if (
|
||||
_sale_in_progress
|
||||
or (
|
||||
|
|
@ -2973,7 +3116,8 @@ func _on_sell_pressed() -> void:
|
|||
return
|
||||
if (
|
||||
_network_sale_service == null
|
||||
or not _network_sale_service.can_request_sale()
|
||||
or buyer_id.is_empty()
|
||||
or not _network_sale_service.can_request_sale(buyer_id)
|
||||
):
|
||||
_transaction_feedback.text = (
|
||||
"Selling is not supported by this server."
|
||||
|
|
@ -2983,13 +3127,13 @@ func _on_sell_pressed() -> void:
|
|||
if (
|
||||
_inventory == null
|
||||
or _sale_service == null
|
||||
or _default_buyer == null
|
||||
or active_buyer == null
|
||||
or selected_ids.is_empty()
|
||||
):
|
||||
return
|
||||
var preview: FishSaleResultType = _sale_service.preview_batch(
|
||||
selected_ids,
|
||||
_default_buyer
|
||||
active_buyer
|
||||
)
|
||||
if not preview.is_success():
|
||||
_transaction_feedback.text = (
|
||||
|
|
@ -3001,8 +3145,8 @@ func _on_sell_pressed() -> void:
|
|||
_refresh_inventory()
|
||||
return
|
||||
_confirmation_catch_ids = selected_ids.duplicate()
|
||||
_confirmation_buyer = _default_buyer
|
||||
_confirmation_buyer_id = _default_buyer.id
|
||||
_confirmation_buyer = active_buyer
|
||||
_confirmation_buyer_id = active_buyer.id
|
||||
_confirmation_generation = _menu_generation
|
||||
var fish_label: String = "fish"
|
||||
_confirmation_message.text = (
|
||||
|
|
@ -3010,12 +3154,14 @@ func _on_sell_pressed() -> void:
|
|||
% [
|
||||
preview.fish_count,
|
||||
fish_label,
|
||||
_get_buyer_display_group(_default_buyer),
|
||||
_get_buyer_display_group(active_buyer),
|
||||
preview.payout,
|
||||
preview.base_value,
|
||||
]
|
||||
)
|
||||
_sale_confirmation.visible = true
|
||||
if _shop_cooler_context_active:
|
||||
shop_cooler_modal_changed.emit(true)
|
||||
_set_shell_interactive(false)
|
||||
for button: Button in [_confirm_sale_button, _cancel_sale_button]:
|
||||
button.focus_mode = Control.FOCUS_ALL
|
||||
|
|
@ -3028,7 +3174,9 @@ func _on_confirm_sale_pressed() -> void:
|
|||
if (
|
||||
_sale_in_progress
|
||||
or _network_sale_service == null
|
||||
or not _network_sale_service.can_request_sale()
|
||||
or not _network_sale_service.can_request_sale(
|
||||
_confirmation_buyer_id
|
||||
)
|
||||
or _sale_service == null
|
||||
or _confirmation_catch_ids.is_empty()
|
||||
or _confirmation_buyer == null
|
||||
|
|
@ -3040,11 +3188,13 @@ func _on_confirm_sale_pressed() -> void:
|
|||
var requested_catch_ids: Array[StringName] = (
|
||||
_confirmation_catch_ids.duplicate()
|
||||
)
|
||||
var requested_buyer_id: StringName = _confirmation_buyer_id
|
||||
var transaction_generation: int = _menu_generation
|
||||
_confirm_sale_button.disabled = true
|
||||
_close_sale_confirmation()
|
||||
var request_id: String = _network_sale_service.request_local_sale(
|
||||
requested_catch_ids
|
||||
requested_catch_ids,
|
||||
requested_buyer_id,
|
||||
)
|
||||
if request_id.is_empty():
|
||||
_sale_in_progress = false
|
||||
|
|
@ -3052,7 +3202,7 @@ func _on_confirm_sale_pressed() -> void:
|
|||
if (
|
||||
_network_sale_service.is_local_sale_pending()
|
||||
and transaction_generation == _menu_generation
|
||||
and visible
|
||||
and (visible or _shop_cooler_context_active)
|
||||
):
|
||||
_transaction_feedback.text = "Selling…"
|
||||
|
||||
|
|
@ -3066,7 +3216,7 @@ func _can_use_shared_world_actions() -> bool:
|
|||
|
||||
func _on_network_sale_pending(_request_id: String) -> void:
|
||||
_sale_in_progress = true
|
||||
if visible:
|
||||
if visible or _shop_cooler_context_active:
|
||||
_transaction_feedback.text = "Selling…"
|
||||
_update_sale_summary()
|
||||
|
||||
|
|
@ -3081,19 +3231,26 @@ func _on_network_sale_finished(
|
|||
_sale_in_progress = false
|
||||
if accepted:
|
||||
_fish_selection.remove_ids(catch_ids)
|
||||
if not visible:
|
||||
if not visible and not _shop_cooler_context_active:
|
||||
return
|
||||
_transaction_feedback.text = (
|
||||
_refresh_all()
|
||||
var feedback_message: String = (
|
||||
"Sale complete. $%d received." % payout
|
||||
if accepted
|
||||
else message
|
||||
)
|
||||
_refresh_all()
|
||||
_transaction_feedback.text = feedback_message
|
||||
if not accepted:
|
||||
_sale_unavailable.text = feedback_message
|
||||
_sale_unavailable.visible = true
|
||||
if _current_section == Section.COOLER:
|
||||
call_deferred("_restore_inventory_tab_focus")
|
||||
|
||||
|
||||
func _restore_inventory_tab_focus() -> void:
|
||||
if _shop_cooler_context_active:
|
||||
_focus_shop_cooler()
|
||||
return
|
||||
if (
|
||||
visible
|
||||
and _current_section == Section.COOLER
|
||||
|
|
@ -3110,6 +3267,8 @@ func _close_sale_confirmation() -> void:
|
|||
_confirmation_buyer_id = StringName()
|
||||
_confirmation_generation = -1
|
||||
_sale_confirmation.visible = false
|
||||
if was_visible and _shop_cooler_context_active:
|
||||
shop_cooler_modal_changed.emit(false)
|
||||
_confirmation_message.text = ""
|
||||
_confirm_sale_button.disabled = false
|
||||
for button: Button in [_confirm_sale_button, _cancel_sale_button]:
|
||||
|
|
@ -3117,7 +3276,7 @@ func _close_sale_confirmation() -> void:
|
|||
button.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
if (
|
||||
was_visible
|
||||
and visible
|
||||
and (visible or _shop_cooler_context_active)
|
||||
and not _transitioning
|
||||
and not _page_transitioning
|
||||
):
|
||||
|
|
@ -3171,6 +3330,22 @@ func _get_buyer_display_group(
|
|||
return "buyer"
|
||||
|
||||
|
||||
func _get_active_sale_buyer() -> FishBuyerProfileType:
|
||||
if _sale_buyer_override != null and _sale_buyer_override.is_valid():
|
||||
return _sale_buyer_override
|
||||
return _default_buyer
|
||||
|
||||
|
||||
func _get_offer_label(buyer: FishBuyerProfileType) -> String:
|
||||
if buyer == null:
|
||||
return "buyer offer"
|
||||
if buyer.id == MAIN_SHOP_BUYER_ID:
|
||||
return "shop offer"
|
||||
if buyer.id == NetworkSaleService.PELICAN_BUYER_ID:
|
||||
return "pelican offer"
|
||||
return "buyer offer"
|
||||
|
||||
|
||||
func _refresh_logbook() -> void:
|
||||
if not is_node_ready():
|
||||
return
|
||||
|
|
|
|||
|
|
@ -487,7 +487,7 @@ mouse_filter = 1
|
|||
|
||||
[node name="BagFilterTabs" type="HBoxContainer" parent="ResponsivePlayerMenuStage/PlayerMenuPresentationScaleRoot/BagPage"]
|
||||
unique_name_in_owner = true
|
||||
z_index = 5
|
||||
z_index = 55
|
||||
layout_mode = 0
|
||||
offset_left = 122.0
|
||||
offset_top = 166.0
|
||||
|
|
@ -1330,12 +1330,12 @@ columns = 4
|
|||
[node name="SaleConfirmation" type="PanelContainer" parent="ResponsivePlayerMenuStage/PlayerMenuPresentationScaleRoot"]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
z_index = 40
|
||||
z_index = 120
|
||||
layout_mode = 0
|
||||
offset_left = 320.0
|
||||
offset_top = 200.0
|
||||
offset_right = 960.0
|
||||
offset_bottom = 520.0
|
||||
offset_left = 380.0
|
||||
offset_top = 265.0
|
||||
offset_right = 840.0
|
||||
offset_bottom = 455.0
|
||||
|
||||
[node name="ConfirmationMargin" type="MarginContainer" parent="ResponsivePlayerMenuStage/PlayerMenuPresentationScaleRoot/SaleConfirmation"]
|
||||
layout_mode = 2
|
||||
|
|
@ -1347,29 +1347,31 @@ theme_override_constants/margin_bottom = 20
|
|||
[node name="ConfirmationLayout" type="VBoxContainer" parent="ResponsivePlayerMenuStage/PlayerMenuPresentationScaleRoot/SaleConfirmation/ConfirmationMargin"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 12
|
||||
alignment = 1
|
||||
|
||||
[node name="ConfirmationMessage" type="Label" parent="ResponsivePlayerMenuStage/PlayerMenuPresentationScaleRoot/SaleConfirmation/ConfirmationMargin/ConfirmationLayout"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
theme_override_font_sizes/font_size = 22
|
||||
autowrap_mode = 2
|
||||
horizontal_alignment = 1
|
||||
|
||||
[node name="ConfirmationButtons" type="HBoxContainer" parent="ResponsivePlayerMenuStage/PlayerMenuPresentationScaleRoot/SaleConfirmation/ConfirmationMargin/ConfirmationLayout"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 10
|
||||
alignment = 1
|
||||
|
||||
[node name="ConfirmSaleButton" type="Button" parent="ResponsivePlayerMenuStage/PlayerMenuPresentationScaleRoot/SaleConfirmation/ConfirmationMargin/ConfirmationLayout/ConfirmationButtons"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
text = "confirm"
|
||||
theme_type_variation = &"DangerButton"
|
||||
custom_minimum_size = Vector2(170, 64)
|
||||
custom_minimum_size = Vector2(140, 44)
|
||||
|
||||
[node name="CancelSaleButton" type="Button" parent="ResponsivePlayerMenuStage/PlayerMenuPresentationScaleRoot/SaleConfirmation/ConfirmationMargin/ConfirmationLayout/ConfirmationButtons"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
text = "cancel"
|
||||
custom_minimum_size = Vector2(170, 64)
|
||||
custom_minimum_size = Vector2(140, 44)
|
||||
|
||||
[node name="NavigationCluster" type="Control" parent="ResponsivePlayerMenuStage/PlayerMenuPresentationScaleRoot"]
|
||||
unique_name_in_owner = true
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@ enum PresentationMode {
|
|||
GAMEPLAY_MODAL,
|
||||
}
|
||||
|
||||
@onready var _backdrop: ColorRect = $Backdrop
|
||||
@onready var _root_page: SettingsBubblePage = %RootPage
|
||||
@onready var _display_page: SettingsBubblePage = %DisplayPage
|
||||
@onready var _controls_page: SettingsBubblePage = %ControlsPage
|
||||
|
|
@ -210,15 +209,10 @@ func open_panel(
|
|||
settings_manager: SettingsManagerType,
|
||||
presentation_mode: PresentationMode = PresentationMode.GAMEPLAY_MODAL,
|
||||
animate_gameplay_host_transitions: bool = false,
|
||||
uses_external_backdrop: bool = false,
|
||||
) -> void:
|
||||
_cancel_page_transition()
|
||||
_presentation_mode = presentation_mode
|
||||
_animate_gameplay_host_transitions = animate_gameplay_host_transitions
|
||||
_backdrop.visible = (
|
||||
presentation_mode == PresentationMode.GAMEPLAY_MODAL
|
||||
and not uses_external_backdrop
|
||||
)
|
||||
_settings_manager = settings_manager
|
||||
_load_controls()
|
||||
_feedback.text = ""
|
||||
|
|
|
|||
|
|
@ -15,16 +15,6 @@ anchors_preset = 0
|
|||
theme = ExtResource("2_theme")
|
||||
script = ExtResource("1_panel")
|
||||
|
||||
[node name="Backdrop" type="ColorRect" parent="."]
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
mouse_filter = 2
|
||||
color = Color(0.025, 0.085, 0.115, 0.72)
|
||||
|
||||
[node name="SettingsFeedback" type="Label" parent="."]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 1
|
||||
|
|
|
|||
|
|
@ -1541,12 +1541,12 @@ func _spawn_decorative_fish(generation: int) -> void:
|
|||
CROSSING_DURATION_MIN,
|
||||
CROSSING_DURATION_MAX
|
||||
)
|
||||
fish_control.position = Vector2(
|
||||
-presentation_size.x - FISH_EDGE_MARGIN
|
||||
if direction > 0.0
|
||||
else layer_size.x + FISH_EDGE_MARGIN,
|
||||
base_y
|
||||
var horizontal_bounds: Vector2 = get_decorative_fish_crossing_bounds(
|
||||
layer_size.x,
|
||||
presentation_size.x,
|
||||
direction,
|
||||
)
|
||||
fish_control.position = Vector2(horizontal_bounds.x, base_y)
|
||||
_decorative_fish_layer.add_child(fish_control)
|
||||
_decorative_fish = fish_control
|
||||
_decorative_fish_tween = create_tween()
|
||||
|
|
@ -1586,17 +1586,14 @@ func _update_decorative_fish(
|
|||
or not is_instance_valid(fish_control)
|
||||
):
|
||||
return
|
||||
var start_x: float = (
|
||||
-fish_control.size.x - FISH_EDGE_MARGIN
|
||||
if direction > 0.0
|
||||
else _decorative_fish_layer.size.x + FISH_EDGE_MARGIN
|
||||
var horizontal_bounds: Vector2 = get_decorative_fish_crossing_bounds(
|
||||
_decorative_fish_layer.size.x,
|
||||
fish_control.size.x,
|
||||
direction,
|
||||
)
|
||||
var end_x: float = (
|
||||
_decorative_fish_layer.size.x + FISH_EDGE_MARGIN
|
||||
if direction > 0.0
|
||||
else -fish_control.size.x - FISH_EDGE_MARGIN
|
||||
fish_control.position.x = lerpf(
|
||||
horizontal_bounds.x, horizontal_bounds.y, progress
|
||||
)
|
||||
fish_control.position.x = lerpf(start_x, end_x, progress)
|
||||
var bobbed_y: float = (
|
||||
base_y
|
||||
+ sin(progress * crossing_duration * bob_speed) * bob_amplitude
|
||||
|
|
@ -1609,6 +1606,20 @@ func _update_decorative_fish(
|
|||
fish_control.position = _snap_world_preview(fish_control.position)
|
||||
|
||||
|
||||
static func get_decorative_fish_crossing_bounds(
|
||||
layer_width: float,
|
||||
fish_width: float,
|
||||
direction: float,
|
||||
) -> Vector2:
|
||||
var outside_left: float = -fish_width - FISH_EDGE_MARGIN
|
||||
var outside_right: float = layer_width + FISH_EDGE_MARGIN
|
||||
return (
|
||||
Vector2(outside_left, outside_right)
|
||||
if direction > 0.0
|
||||
else Vector2(outside_right, outside_left)
|
||||
)
|
||||
|
||||
|
||||
func _on_decorative_fish_finished(
|
||||
fish_control: TextureRect,
|
||||
generation: int,
|
||||
|
|
|
|||
|
|
@ -13,6 +13,13 @@ signal effective_pixel_size_changed(
|
|||
|
||||
@onready var _ui_viewport: SubViewport = $UIViewport
|
||||
@onready var _ui_root: Control = $UIViewport/GameUI/UIRoot
|
||||
@onready var _canonical_stage: Control = (
|
||||
$UIViewport/GameUI/UIRoot/CanonicalStage
|
||||
)
|
||||
@onready var _chat_ui: ChatUI = $UIViewport/GameUI/UIRoot/ChatUI
|
||||
@onready var _title_content_stage: Control = (
|
||||
$UIViewport/GameUI/UIRoot/TitleScreen/ResponsiveTitleStage
|
||||
)
|
||||
|
||||
var _requested_pixel_size: int = PlayerSettings.DEFAULT_UI_PIXEL_SIZE
|
||||
var _effective_pixel_size: int = PlayerSettings.DEFAULT_UI_PIXEL_SIZE
|
||||
|
|
@ -94,21 +101,29 @@ func _resize_presentation() -> void:
|
|||
float(render_height)
|
||||
/ UIReferencePresentationType.REFERENCE_SIZE.y
|
||||
)
|
||||
var visible_reference_size: Vector2 = (
|
||||
UIReferencePresentationType.get_visible_reference_size(display_size)
|
||||
)
|
||||
var viewport_size := Vector2i(
|
||||
roundi(
|
||||
UIReferencePresentationType.REFERENCE_SIZE.x
|
||||
* render_scale
|
||||
),
|
||||
render_height,
|
||||
roundi(visible_reference_size.x * render_scale),
|
||||
roundi(visible_reference_size.y * render_scale),
|
||||
)
|
||||
set_anchors_preset(Control.PRESET_TOP_LEFT)
|
||||
position = UIReferencePresentationType.get_offset(display_size)
|
||||
position = Vector2.ZERO
|
||||
size = Vector2(viewport_size)
|
||||
scale = Vector2.ONE * (reference_scale / render_scale)
|
||||
stretch_shrink = 1
|
||||
_ui_root.position = Vector2.ZERO
|
||||
_ui_root.scale = Vector2.ONE * render_scale
|
||||
_ui_root.size = UIReferencePresentationType.REFERENCE_SIZE
|
||||
_ui_root.size = visible_reference_size
|
||||
_canonical_stage.position = (
|
||||
UIReferencePresentationType.get_stage_position(display_size)
|
||||
)
|
||||
_canonical_stage.size = UIReferencePresentationType.REFERENCE_SIZE
|
||||
_title_content_stage.set_anchors_preset(Control.PRESET_TOP_LEFT)
|
||||
_title_content_stage.position = _canonical_stage.position
|
||||
_title_content_stage.size = UIReferencePresentationType.REFERENCE_SIZE
|
||||
_chat_ui.set_output_scale(reference_scale)
|
||||
if (
|
||||
previous_effective_size != _effective_pixel_size
|
||||
or _requested_pixel_size != _effective_pixel_size
|
||||
|
|
|
|||
|
|
@ -1,6 +1,15 @@
|
|||
class_name UIReferencePresentation
|
||||
extends RefCounted
|
||||
|
||||
# All functional UI is authored in this coordinate system and receives one
|
||||
# centered, uniform transform at presentation time. Texture source dimensions
|
||||
# describe sampling quality and aspect ratio; a canonical Control rect owns
|
||||
# every texture's on-screen layout size.
|
||||
#
|
||||
# Edge-docked overlays use the same canonical units and uniform scale, but may
|
||||
# use the extra logical canvas outside the centered stage on non-16:9 windows.
|
||||
# This keeps deliberate window-edge attachment without letting individual
|
||||
# controls calculate monitor- or DPI-specific geometry.
|
||||
const REFERENCE_SIZE: Vector2 = Vector2(1280.0, 720.0)
|
||||
|
||||
|
||||
|
|
@ -18,6 +27,14 @@ static func get_offset(display_size: Vector2) -> Vector2:
|
|||
) * 0.5
|
||||
|
||||
|
||||
static func get_visible_reference_size(display_size: Vector2) -> Vector2:
|
||||
return display_size / get_scale(display_size)
|
||||
|
||||
|
||||
static func get_stage_position(display_size: Vector2) -> Vector2:
|
||||
return (get_visible_reference_size(display_size) - REFERENCE_SIZE) * 0.5
|
||||
|
||||
|
||||
static func get_rect(display_size: Vector2) -> Rect2:
|
||||
var presentation_scale: float = get_scale(display_size)
|
||||
return Rect2(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue