330 lines
9.7 KiB
GDScript
330 lines
9.7 KiB
GDScript
class_name RVUpgradeShop
|
|
extends Control
|
|
|
|
const INPUT_OWNER: StringName = &"rv_upgrade_shop"
|
|
const UtilityPageStyleType = preload("res://ui/utility_page_style.gd")
|
|
const CurrencyPresentationType = preload("res://ui/currency_presentation.gd")
|
|
|
|
signal menu_visibility_changed(is_open: bool)
|
|
signal menu_exit_started
|
|
|
|
var _player: Player
|
|
var _wallet: PlayerWallet
|
|
var _fishing_spot: FishingSpot
|
|
var _interaction: RVUpgradeInteraction
|
|
var _home_state: PlayerHomeState
|
|
var _network_shop: NetworkShopService
|
|
var _wallet_amount: CurrencyAmount
|
|
var _price_amount: CurrencyAmount
|
|
var _home_label: Label
|
|
var _storage_label: Label
|
|
var _feedback: Label
|
|
var _upgrade_button: Button
|
|
var _close_button: Button
|
|
var _transaction_pending: bool = false
|
|
var _prior_movement_enabled: bool = true
|
|
var _prior_camera_enabled: bool = true
|
|
var _prior_mouse_mode: Input.MouseMode = Input.MOUSE_MODE_VISIBLE
|
|
|
|
|
|
func _ready() -> void:
|
|
UtilityPageStyleType.apply_page(self)
|
|
_build_ui()
|
|
hide()
|
|
|
|
|
|
func setup(
|
|
player: Player,
|
|
wallet: PlayerWallet,
|
|
fishing_spot: FishingSpot,
|
|
interaction: RVUpgradeInteraction,
|
|
home_state: PlayerHomeState,
|
|
network_shop: NetworkShopService,
|
|
) -> void:
|
|
_player = player
|
|
_wallet = wallet
|
|
_fishing_spot = fishing_spot
|
|
_interaction = interaction
|
|
_home_state = home_state
|
|
_network_shop = network_shop
|
|
if not _wallet.balance_changed.is_connected(_on_wallet_changed):
|
|
_wallet.balance_changed.connect(_on_wallet_changed)
|
|
if not _home_state.changed.is_connected(_refresh):
|
|
_home_state.changed.connect(_refresh)
|
|
if (
|
|
_network_shop != null
|
|
and not _network_shop.local_purchase_pending.is_connected(
|
|
_on_purchase_pending
|
|
)
|
|
):
|
|
_network_shop.local_purchase_pending.connect(_on_purchase_pending)
|
|
_network_shop.local_purchase_finished.connect(_on_purchase_finished)
|
|
_refresh()
|
|
|
|
|
|
func set_world_interaction(interaction: RVUpgradeInteraction) -> void:
|
|
_interaction = interaction
|
|
|
|
|
|
func open_shop() -> bool:
|
|
if (
|
|
visible
|
|
or _player == null
|
|
or _wallet == null
|
|
or _fishing_spot == null
|
|
or _interaction == null
|
|
or not _interaction.is_local_player_in_range()
|
|
or not _fishing_spot.can_open_fishing_shop()
|
|
):
|
|
return false
|
|
_prior_movement_enabled = _player.is_movement_enabled()
|
|
_prior_camera_enabled = _player.is_camera_input_enabled()
|
|
_player.set_movement_enabled(false)
|
|
_player.set_camera_input_enabled(false)
|
|
_prior_mouse_mode = _restorable_mouse_mode(Input.mouse_mode)
|
|
_fishing_spot.set_local_menu_input_suppressed(INPUT_OWNER, true)
|
|
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
|
|
_transaction_pending = (
|
|
_network_shop != null
|
|
and _network_shop.is_local_purchase_pending()
|
|
)
|
|
_feedback.text = ""
|
|
_refresh()
|
|
show()
|
|
_upgrade_button.call_deferred("grab_focus")
|
|
menu_visibility_changed.emit(true)
|
|
return true
|
|
|
|
|
|
func close_shop(restore_controls: bool = true) -> void:
|
|
if not visible:
|
|
return
|
|
menu_exit_started.emit()
|
|
get_viewport().gui_release_focus()
|
|
hide()
|
|
if _fishing_spot != null:
|
|
_fishing_spot.set_local_menu_input_suppressed(INPUT_OWNER, false)
|
|
if restore_controls and _player != null:
|
|
_player.set_movement_enabled(_prior_movement_enabled)
|
|
_player.set_camera_input_enabled(_prior_camera_enabled)
|
|
Input.mouse_mode = _prior_mouse_mode
|
|
menu_visibility_changed.emit(false)
|
|
|
|
|
|
func consume_escape() -> bool:
|
|
if not visible:
|
|
return false
|
|
close_shop()
|
|
return true
|
|
|
|
|
|
func close_for_range_exit() -> void:
|
|
close_shop()
|
|
|
|
|
|
func close_for_water_recovery() -> void:
|
|
close_shop(false)
|
|
|
|
|
|
func close_for_session_end() -> void:
|
|
close_shop(false)
|
|
|
|
|
|
func _unhandled_input(event: InputEvent) -> void:
|
|
if not visible or not event.is_action_pressed("ui_cancel"):
|
|
return
|
|
close_shop()
|
|
get_viewport().set_input_as_handled()
|
|
|
|
|
|
func _purchase_upgrade() -> void:
|
|
if _network_shop == null or _transaction_pending:
|
|
return
|
|
var request_id: String = _network_shop.request_home_upgrade()
|
|
if request_id.is_empty():
|
|
_refresh()
|
|
|
|
|
|
func _on_purchase_pending(_request_id: String) -> void:
|
|
_transaction_pending = true
|
|
_feedback.text = "upgrading…"
|
|
_refresh()
|
|
|
|
|
|
func _on_purchase_finished(
|
|
_request_id: String,
|
|
accepted: bool,
|
|
message: String,
|
|
product_id: StringName,
|
|
category: int,
|
|
_quantity: int,
|
|
_total_cost: int,
|
|
) -> void:
|
|
if (
|
|
category != NetworkShopProtocol.ProductCategory.HOME_UPGRADE
|
|
or product_id != NetworkShopService.HOME_UPGRADE_PRODUCT_ID
|
|
):
|
|
return
|
|
_transaction_pending = false
|
|
_feedback.text = "starter RV unlocked" if accepted else message.to_lower()
|
|
_refresh()
|
|
|
|
|
|
func _on_wallet_changed(_balance: int, _delta: int) -> void:
|
|
_refresh()
|
|
|
|
|
|
func _refresh() -> void:
|
|
if _wallet_amount == null:
|
|
return
|
|
var balance: int = _wallet.get_balance() if _wallet != null else 0
|
|
var tier: int = _home_state.get_tier() if _home_state != null else 0
|
|
var current_capacity: int = (
|
|
_home_state.get_storage_capacity() if _home_state != null else 9
|
|
)
|
|
var next_capacity: int = (
|
|
_home_state.get_next_storage_capacity() if _home_state != null else -1
|
|
)
|
|
var cost: int = (
|
|
_home_state.get_next_upgrade_cost() if _home_state != null else -1
|
|
)
|
|
_wallet_amount.set_amount(balance)
|
|
_price_amount.set_amount(maxi(cost, 0))
|
|
if tier >= PlayerHomeState.MAX_TIER:
|
|
_home_label.text = "starter RV"
|
|
_storage_label.text = "storage · %d slots" % current_capacity
|
|
_upgrade_button.text = "unlocked"
|
|
_upgrade_button.disabled = true
|
|
_price_amount.visible = false
|
|
else:
|
|
_home_label.text = "tent → starter RV"
|
|
_storage_label.text = "storage · %d → %d slots" % [
|
|
current_capacity, next_capacity,
|
|
]
|
|
_upgrade_button.text = "upgrade"
|
|
_upgrade_button.disabled = (
|
|
_transaction_pending
|
|
or _wallet == null
|
|
or not _wallet.can_afford(cost)
|
|
or _network_shop == null
|
|
or not _network_shop.can_request_home_upgrade()
|
|
)
|
|
_price_amount.visible = true
|
|
|
|
|
|
func _restorable_mouse_mode(mouse_mode: Input.MouseMode) -> Input.MouseMode:
|
|
return (
|
|
Input.MOUSE_MODE_VISIBLE
|
|
if mouse_mode == Input.MOUSE_MODE_CAPTURED
|
|
else mouse_mode
|
|
)
|
|
|
|
|
|
func _build_ui() -> void:
|
|
set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
|
z_index = 83
|
|
mouse_filter = Control.MOUSE_FILTER_STOP
|
|
var blocker := ColorRect.new()
|
|
blocker.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
|
blocker.color = Color(0.02, 0.08, 0.10, 0.55)
|
|
blocker.mouse_filter = Control.MOUSE_FILTER_STOP
|
|
add_child(blocker)
|
|
|
|
var panel := PanelContainer.new()
|
|
panel.set_anchors_preset(Control.PRESET_CENTER)
|
|
panel.position = Vector2(-390.0, -225.0)
|
|
panel.size = Vector2(780.0, 450.0)
|
|
panel.add_theme_stylebox_override(
|
|
"panel",
|
|
UtilityPageStyleType.rounded_style(
|
|
UtilityPageStyleType.OCEAN_PANEL_DEEP, 24
|
|
),
|
|
)
|
|
add_child(panel)
|
|
var margin := MarginContainer.new()
|
|
for side: StringName in [
|
|
&"margin_left", &"margin_top", &"margin_right", &"margin_bottom",
|
|
]:
|
|
margin.add_theme_constant_override(side, 28)
|
|
panel.add_child(margin)
|
|
var layout := VBoxContainer.new()
|
|
layout.add_theme_constant_override("separation", 18)
|
|
margin.add_child(layout)
|
|
|
|
var header := HBoxContainer.new()
|
|
header.add_theme_constant_override("separation", 12)
|
|
layout.add_child(header)
|
|
var title := Label.new()
|
|
title.text = "home upgrades"
|
|
title.add_theme_font_size_override("font_size", 38)
|
|
title.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
|
header.add_child(title)
|
|
_wallet_amount = CurrencyPresentationType.instantiate_amount(0, 24.0)
|
|
header.add_child(_wallet_amount)
|
|
|
|
var offer := PanelContainer.new()
|
|
offer.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
|
offer.add_theme_stylebox_override(
|
|
"panel",
|
|
UtilityPageStyleType.rounded_style(
|
|
UtilityPageStyleType.OCEAN_FIELD, 18
|
|
),
|
|
)
|
|
layout.add_child(offer)
|
|
var offer_margin := MarginContainer.new()
|
|
for side: StringName in [
|
|
&"margin_left", &"margin_top", &"margin_right", &"margin_bottom",
|
|
]:
|
|
offer_margin.add_theme_constant_override(side, 28)
|
|
offer.add_child(offer_margin)
|
|
var details := VBoxContainer.new()
|
|
details.alignment = BoxContainer.ALIGNMENT_CENTER
|
|
details.add_theme_constant_override("separation", 14)
|
|
offer_margin.add_child(details)
|
|
_home_label = Label.new()
|
|
_home_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
|
_home_label.add_theme_font_size_override("font_size", 34)
|
|
details.add_child(_home_label)
|
|
var description := Label.new()
|
|
description.text = (
|
|
"A weatherproof home with a larger interior and built-in storage."
|
|
)
|
|
description.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
|
description.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
|
description.add_theme_font_size_override("font_size", 20)
|
|
details.add_child(description)
|
|
_storage_label = Label.new()
|
|
_storage_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
|
_storage_label.add_theme_font_size_override("font_size", 22)
|
|
details.add_child(_storage_label)
|
|
var purchase_row := HBoxContainer.new()
|
|
purchase_row.alignment = BoxContainer.ALIGNMENT_CENTER
|
|
purchase_row.add_theme_constant_override("separation", 10)
|
|
details.add_child(purchase_row)
|
|
_upgrade_button = Button.new()
|
|
_upgrade_button.custom_minimum_size = Vector2(220.0, 60.0)
|
|
UtilityPageStyleType.apply_ocean_button(_upgrade_button)
|
|
_upgrade_button.pressed.connect(_purchase_upgrade)
|
|
purchase_row.add_child(_upgrade_button)
|
|
_price_amount = CurrencyPresentationType.instantiate_amount(0, 24.0)
|
|
purchase_row.add_child(_price_amount)
|
|
|
|
var footer := HBoxContainer.new()
|
|
footer.add_theme_constant_override("separation", 12)
|
|
layout.add_child(footer)
|
|
_feedback = Label.new()
|
|
_feedback.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
|
_feedback.add_theme_font_size_override("font_size", 18)
|
|
footer.add_child(_feedback)
|
|
_close_button = Button.new()
|
|
_close_button.text = "close"
|
|
_close_button.custom_minimum_size = Vector2(150.0, 50.0)
|
|
UtilityPageStyleType.apply_ocean_button(_close_button)
|
|
_close_button.pressed.connect(close_shop)
|
|
footer.add_child(_close_button)
|
|
_upgrade_button.focus_neighbor_bottom = _upgrade_button.get_path_to(
|
|
_close_button
|
|
)
|
|
_close_button.focus_neighbor_top = _close_button.get_path_to(
|
|
_upgrade_button
|
|
)
|