Add starter RV progression and fishing feedback
This commit is contained in:
parent
eed361681a
commit
d8bf59bca0
47 changed files with 2268 additions and 467 deletions
10
ui/fishing_danger_vignette.gdshader
Normal file
10
ui/fishing_danger_vignette.gdshader
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
shader_type canvas_item;
|
||||
|
||||
uniform float intensity : hint_range(0.0, 1.0) = 0.0;
|
||||
|
||||
void fragment() {
|
||||
vec2 centered = UV * 2.0 - 1.0;
|
||||
centered.x *= 0.56;
|
||||
float edge = smoothstep(0.42, 1.02, length(centered));
|
||||
COLOR = vec4(0.16, 0.018, 0.025, edge * intensity * 0.72);
|
||||
}
|
||||
1
ui/fishing_danger_vignette.gdshader.uid
Normal file
1
ui/fishing_danger_vignette.gdshader.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://c1qcj3m4b10x4
|
||||
|
|
@ -15,9 +15,6 @@ const PlayerFishingUpgradesType = preload(
|
|||
"res://progression/player_fishing_upgrades.gd"
|
||||
)
|
||||
const PlayerType = preload("res://player/player.gd")
|
||||
const PlayerCoolerCapacityType = preload(
|
||||
"res://progression/player_cooler_capacity.gd"
|
||||
)
|
||||
const PlayerArtUnlocksType = preload(
|
||||
"res://progression/player_art_unlocks.gd"
|
||||
)
|
||||
|
|
@ -154,9 +151,6 @@ const ROD_PRICE_ICON_SIZE: float = 22.0
|
|||
@onready var _barrier_price_bubble: PanelContainer = %BarrierPriceBubble
|
||||
@onready var _barrier_purchase: Button = %BarrierPurchase
|
||||
@onready var _supplies_list: VBoxContainer = %SuppliesList
|
||||
@onready var _cooler_cost: CurrencyAmount = %CoolerCost
|
||||
@onready var _cooler_price_bubble: PanelContainer = %CoolerPriceBubble
|
||||
@onready var _cooler_purchase: Button = %CoolerPurchase
|
||||
@onready var _backpack_cost: CurrencyAmount = %BackpackCost
|
||||
@onready var _backpack_price_bubble: PanelContainer = %BackpackPriceBubble
|
||||
@onready var _backpack_purchase: Button = %BackpackPurchase
|
||||
|
|
@ -172,7 +166,6 @@ var _inventory: FishInventory
|
|||
var _hotbar: PlayerHotbar
|
||||
var _inventory_layout: PlayerInventoryLayout
|
||||
var _item_catalog: ItemCatalogType
|
||||
var _cooler_capacity: PlayerCoolerCapacityType
|
||||
var _art_unlocks: PlayerArtUnlocksType
|
||||
var _network_shop: NetworkShopService
|
||||
var _network_sale: NetworkSaleService
|
||||
|
|
@ -202,7 +195,6 @@ func _ready() -> void:
|
|||
%CloseButton.pressed.connect(close_shop)
|
||||
_reel_purchase.pressed.connect(_purchase_reel_speed)
|
||||
_barrier_purchase.pressed.connect(_purchase_barrier_power)
|
||||
_cooler_purchase.pressed.connect(_purchase_cooler_capacity)
|
||||
_backpack_purchase.pressed.connect(_purchase_backpack_capacity)
|
||||
|
||||
|
||||
|
|
@ -353,7 +345,6 @@ func _focus_shop_section() -> void:
|
|||
for upgrade_button: Button in [
|
||||
_reel_purchase,
|
||||
_barrier_purchase,
|
||||
_cooler_purchase,
|
||||
_backpack_purchase,
|
||||
]:
|
||||
if not upgrade_button.disabled:
|
||||
|
|
@ -509,7 +500,6 @@ func _apply_shop_styles() -> void:
|
|||
for panel: PanelContainer in [
|
||||
_reel_price_bubble,
|
||||
_barrier_price_bubble,
|
||||
_cooler_price_bubble,
|
||||
_backpack_price_bubble,
|
||||
]:
|
||||
var price_style := UtilityPageStyleType.rounded_style(
|
||||
|
|
@ -526,7 +516,6 @@ func _apply_shop_styles() -> void:
|
|||
for price: CurrencyAmount in [
|
||||
_reel_cost,
|
||||
_barrier_cost,
|
||||
_cooler_cost,
|
||||
_backpack_cost,
|
||||
]:
|
||||
var amount_label := price.get_amount_label()
|
||||
|
|
@ -538,7 +527,6 @@ func _apply_shop_styles() -> void:
|
|||
%CloseButton,
|
||||
_reel_purchase,
|
||||
_barrier_purchase,
|
||||
_cooler_purchase,
|
||||
_backpack_purchase,
|
||||
]:
|
||||
UtilityPageStyleType.apply_ocean_button(button)
|
||||
|
|
@ -559,7 +547,6 @@ func setup(
|
|||
hotbar: PlayerHotbar,
|
||||
inventory_layout: PlayerInventoryLayout,
|
||||
item_catalog: ItemCatalogType,
|
||||
cooler_capacity: PlayerCoolerCapacityType,
|
||||
art_unlocks: PlayerArtUnlocksType,
|
||||
network_shop: NetworkShopService,
|
||||
network_sale: NetworkSaleService,
|
||||
|
|
@ -576,7 +563,6 @@ func setup(
|
|||
_hotbar = hotbar
|
||||
_inventory_layout = inventory_layout
|
||||
_item_catalog = item_catalog
|
||||
_cooler_capacity = cooler_capacity
|
||||
_art_unlocks = art_unlocks
|
||||
_network_shop = network_shop
|
||||
_network_sale = network_sale
|
||||
|
|
@ -612,10 +598,6 @@ func setup(
|
|||
_upgrades.upgrades_changed.connect(_on_upgrades_changed)
|
||||
if not _bag.contents_changed.is_connected(_on_bag_changed):
|
||||
_bag.contents_changed.connect(_on_bag_changed)
|
||||
if not _cooler_capacity.capacity_changed.is_connected(
|
||||
_on_cooler_capacity_changed
|
||||
):
|
||||
_cooler_capacity.capacity_changed.connect(_on_cooler_capacity_changed)
|
||||
if not _inventory_layout.backpack_capacity_changed.is_connected(
|
||||
_on_backpack_capacity_changed
|
||||
):
|
||||
|
|
@ -836,7 +818,6 @@ func _refresh_all() -> void:
|
|||
_refresh_wallet()
|
||||
_refresh_upgrades()
|
||||
_refresh_supplies()
|
||||
_refresh_cooler_capacity()
|
||||
_refresh_backpack_capacity()
|
||||
|
||||
|
||||
|
|
@ -1587,41 +1568,6 @@ func _add_supply_icon_tile(
|
|||
return tile_host
|
||||
|
||||
|
||||
func _refresh_cooler_capacity() -> void:
|
||||
if _cooler_capacity == null:
|
||||
return
|
||||
var level: int = _cooler_capacity.get_level()
|
||||
var cost: int = _cooler_capacity.get_next_cost()
|
||||
var next_capacity: int = _cooler_capacity.get_next_capacity()
|
||||
_cooler_purchase.disabled = (
|
||||
cost < 0
|
||||
or _transaction_in_progress
|
||||
or _closing
|
||||
or _network_shop == null
|
||||
or not _network_shop.can_request_purchase()
|
||||
or not _cooler_capacity.can_purchase(_wallet)
|
||||
)
|
||||
var cooler_effect: String
|
||||
if cost < 0:
|
||||
cooler_effect = "%d slots · maximum level" % (
|
||||
_cooler_capacity.get_capacity()
|
||||
)
|
||||
_cooler_price_bubble.hide()
|
||||
else:
|
||||
_cooler_price_bubble.show()
|
||||
cooler_effect = "%d → %d slots" % [
|
||||
_cooler_capacity.get_capacity(),
|
||||
next_capacity,
|
||||
]
|
||||
_cooler_cost.set_amount(cost)
|
||||
_cooler_purchase.tooltip_text = _upgrade_tooltip(
|
||||
"storage capacity",
|
||||
level,
|
||||
cooler_effect,
|
||||
)
|
||||
_cooler_purchase.accessibility_name = _cooler_purchase.tooltip_text
|
||||
|
||||
|
||||
func _refresh_backpack_capacity() -> void:
|
||||
if _inventory_layout == null:
|
||||
return
|
||||
|
|
@ -1723,23 +1669,6 @@ func _purchase_art_upgrade(product_id: StringName) -> void:
|
|||
_network_shop.request_art_upgrade(product_id)
|
||||
|
||||
|
||||
func _purchase_cooler_capacity() -> void:
|
||||
if _transaction_in_progress or not _is_transaction_context_valid():
|
||||
_set_feedback("unable to complete purchase.")
|
||||
return
|
||||
var cost: int = _cooler_capacity.get_next_cost()
|
||||
if cost < 0:
|
||||
_set_feedback("Upgrade is already at maximum.")
|
||||
return
|
||||
if not _wallet.can_afford(cost):
|
||||
_set_feedback("Insufficient funds.")
|
||||
return
|
||||
if _network_shop == null:
|
||||
_set_feedback("Purchase could not be completed.")
|
||||
return
|
||||
_network_shop.request_cooler_capacity_upgrade()
|
||||
|
||||
|
||||
func _purchase_backpack_capacity() -> void:
|
||||
if _transaction_in_progress or not _is_transaction_context_valid():
|
||||
_set_feedback("unable to complete purchase.")
|
||||
|
|
@ -1860,7 +1789,6 @@ func _on_wallet_changed(_balance: int, _delta: int) -> void:
|
|||
_refresh_wallet()
|
||||
_refresh_upgrades()
|
||||
_refresh_supplies()
|
||||
_refresh_cooler_capacity()
|
||||
_refresh_backpack_capacity()
|
||||
|
||||
|
||||
|
|
@ -1875,10 +1803,6 @@ func _on_bag_changed() -> void:
|
|||
_refresh_supplies()
|
||||
|
||||
|
||||
func _on_cooler_capacity_changed(_level: int, _capacity: int) -> void:
|
||||
_refresh_cooler_capacity()
|
||||
|
||||
|
||||
func _on_backpack_capacity_changed(_level: int, _capacity: int) -> void:
|
||||
_refresh_backpack_capacity()
|
||||
|
||||
|
|
|
|||
|
|
@ -257,35 +257,6 @@ layout_mode = 2
|
|||
amount = 100
|
||||
icon_size = 24.0
|
||||
|
||||
[node name="CoolerTile" type="Control" parent="ShopPanel/Margin/Layout/Body/Upgrades/UpgradeScroll/UpgradeGrid"]
|
||||
custom_minimum_size = Vector2(144, 168)
|
||||
layout_mode = 2
|
||||
mouse_filter = 2
|
||||
|
||||
[node name="CoolerPurchase" type="Button" parent="ShopPanel/Margin/Layout/Body/Upgrades/UpgradeScroll/UpgradeGrid/CoolerTile"]
|
||||
unique_name_in_owner = true
|
||||
offset_right = 144.0
|
||||
offset_bottom = 144.0
|
||||
tooltip_text = "storage capacity"
|
||||
icon = ExtResource("7_close")
|
||||
expand_icon = true
|
||||
icon_max_width = 92
|
||||
|
||||
[node name="CoolerPriceBubble" type="PanelContainer" parent="ShopPanel/Margin/Layout/Body/Upgrades/UpgradeScroll/UpgradeGrid/CoolerTile"]
|
||||
unique_name_in_owner = true
|
||||
z_index = 2
|
||||
offset_left = 22.0
|
||||
offset_top = 128.0
|
||||
offset_right = 122.0
|
||||
offset_bottom = 160.0
|
||||
mouse_filter = 2
|
||||
|
||||
[node name="CoolerCost" parent="ShopPanel/Margin/Layout/Body/Upgrades/UpgradeScroll/UpgradeGrid/CoolerTile/CoolerPriceBubble" instance=ExtResource("8_currency")]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
amount = 75
|
||||
icon_size = 24.0
|
||||
|
||||
[node name="BackpackTile" type="Control" parent="ShopPanel/Margin/Layout/Body/Upgrades/UpgradeScroll/UpgradeGrid"]
|
||||
custom_minimum_size = Vector2(144, 168)
|
||||
layout_mode = 2
|
||||
|
|
|
|||
153
ui/game_ui.gd
153
ui/game_ui.gd
|
|
@ -21,6 +21,7 @@ const PauseMenuType = preload("res://ui/pause_menu.gd")
|
|||
const NetworkSessionType = preload("res://network/network_session.gd")
|
||||
const FishingShopType = preload("res://ui/fishing_shop.gd")
|
||||
const DecorShopType = preload("res://ui/decor_shop.gd")
|
||||
const RVUpgradeShopType = preload("res://ui/rv_upgrade_shop.gd")
|
||||
const SettingsPanelType = preload("res://ui/settings_panel.gd")
|
||||
const PlayerFishingUpgradesType = preload(
|
||||
"res://progression/player_fishing_upgrades.gd"
|
||||
|
|
@ -31,6 +32,9 @@ const ShopInteractionType = preload(
|
|||
const DecorShopInteractionType = preload(
|
||||
"res://world/decor_shop_interaction.gd"
|
||||
)
|
||||
const RVUpgradeInteractionType = preload(
|
||||
"res://world/rv_upgrade_interaction.gd"
|
||||
)
|
||||
const PlayerStorageType = preload("res://ui/player_storage.gd")
|
||||
const HomeDecorToolbarType = preload("res://ui/home_decor_toolbar.gd")
|
||||
const PlayerStorageInteractionType = preload(
|
||||
|
|
@ -129,6 +133,7 @@ const FISHING_PANEL_SHOWCASE_BOTTOM_OFFSET: float = -104.0
|
|||
@onready var _barrier_health: Label = %BarrierHealth
|
||||
@onready var _showcase_details: Label = %ShowcaseDetails
|
||||
@onready var _fishing_panel: PanelContainer = %FishingPanel
|
||||
@onready var _fishing_danger_vignette: ColorRect = %FishingDangerVignette
|
||||
@onready var _experience_panel: PanelContainer = %ExperienceProgressPanel
|
||||
@onready var _experience_level_label: Label = %ExperienceLevelLabel
|
||||
@onready var _experience_award_label: Label = %ExperienceAwardLabel
|
||||
|
|
@ -144,6 +149,8 @@ const SHOP_ANIMALESE_VOICE_ID: String = "natural"
|
|||
const SHOP_ANIMALESE_BASE_PITCH: float = 1.08
|
||||
const SHOP_SPEECH_CHARACTERS_PER_SECOND: float = 28.0
|
||||
const SHOP_NPC_SPEECH_COOLDOWN_MILLISECONDS: int = 5000
|
||||
const FISHING_DANGER_START_GAP: float = 0.15
|
||||
const FISHING_DANGER_FULL_GAP: float = 0.025
|
||||
|
||||
|
||||
@onready var _canonical_stage: Control = %CanonicalStage
|
||||
|
|
@ -155,6 +162,7 @@ const SHOP_NPC_SPEECH_COOLDOWN_MILLISECONDS: int = 5000
|
|||
@onready var _hotbar_ui: HotbarUIType = %Hotbar
|
||||
@onready var _fishing_shop: FishingShopType = %FishingShop
|
||||
@onready var _decor_shop: DecorShopType = %DecorShop
|
||||
@onready var _rv_upgrade_shop: RVUpgradeShopType = %RVUpgradeShop
|
||||
@onready var _player_storage: PlayerStorageType = %PlayerStorage
|
||||
@onready var _home_decor_toolbar: HomeDecorToolbarType = %HomeDecorToolbar
|
||||
@onready var _rv_storage_button: Button = %RVStorageButton
|
||||
|
|
@ -208,6 +216,7 @@ var _player_menu_hotbar_visible: bool = false
|
|||
var _main_shop_buyer: FishBuyerProfileType
|
||||
var _shop_interaction: ShopInteractionType
|
||||
var _decor_shop_interaction: DecorShopInteractionType
|
||||
var _rv_upgrade_shop_interaction: RVUpgradeInteractionType
|
||||
var _storage_interaction: PlayerStorageInteractionType
|
||||
var _surface_drawing: NetworkSurfaceDrawingService
|
||||
var _surface_drawing_hotbar_selected: bool = false
|
||||
|
|
@ -235,6 +244,12 @@ var _controller_text_entry_is_open: Callable
|
|||
var _controller_text_entry_close: Callable
|
||||
var _restore_chat_keyboard_after_fishing: bool = false
|
||||
var _rv_storage_button_requested_visible: bool = false
|
||||
var _previous_barrier_health := PackedInt32Array()
|
||||
var _barrier_feedback_initialized: bool = false
|
||||
var _fishing_danger_target: float = 0.0
|
||||
var _fishing_danger_intensity: float = 0.0
|
||||
var _fishing_danger_pulse_time: float = 0.0
|
||||
var _catch_track_shake_tween: Tween
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
|
|
@ -363,6 +378,7 @@ func setup(
|
|||
shop_interaction: ShopInteractionType,
|
||||
storage_interaction: PlayerStorageInteractionType,
|
||||
decor_shop_interaction: DecorShopInteractionType,
|
||||
rv_upgrade_shop_interaction: RVUpgradeInteractionType,
|
||||
item_effects: PlayerItemEffectsType,
|
||||
cooler_capacity: PlayerCoolerCapacityType,
|
||||
network_session: NetworkSessionType,
|
||||
|
|
@ -506,7 +522,6 @@ func setup(
|
|||
hotbar,
|
||||
inventory_layout,
|
||||
item_catalog,
|
||||
cooler_capacity,
|
||||
art_unlocks,
|
||||
network_shop_service,
|
||||
network_sale_service,
|
||||
|
|
@ -521,6 +536,14 @@ func setup(
|
|||
home_state,
|
||||
network_shop_service,
|
||||
)
|
||||
_rv_upgrade_shop.setup(
|
||||
player,
|
||||
wallet,
|
||||
fishing_spot,
|
||||
rv_upgrade_shop_interaction,
|
||||
home_state,
|
||||
network_shop_service,
|
||||
)
|
||||
_player_storage.setup(
|
||||
player,
|
||||
fishing_spot,
|
||||
|
|
@ -538,6 +561,8 @@ func setup(
|
|||
_fishing_shop.menu_exit_started.connect(_on_shop_exit_started)
|
||||
_decor_shop.menu_visibility_changed.connect(_on_shop_visibility_changed)
|
||||
_decor_shop.menu_exit_started.connect(_on_shop_exit_started)
|
||||
_rv_upgrade_shop.menu_visibility_changed.connect(_on_shop_visibility_changed)
|
||||
_rv_upgrade_shop.menu_exit_started.connect(_on_shop_exit_started)
|
||||
_fishing_shop.sell_fish_requested.connect(_on_shop_sell_fish_requested)
|
||||
_fishing_shop.shop_cooler_return_requested.connect(
|
||||
_on_shop_cooler_return_requested
|
||||
|
|
@ -548,6 +573,7 @@ func setup(
|
|||
_main_shop_buyer = main_shop_buyer
|
||||
_shop_interaction = shop_interaction
|
||||
_decor_shop_interaction = decor_shop_interaction
|
||||
_rv_upgrade_shop_interaction = rv_upgrade_shop_interaction
|
||||
_storage_interaction = storage_interaction
|
||||
_surface_drawing = surface_drawing
|
||||
if (
|
||||
|
|
@ -571,13 +597,16 @@ func set_world_interactions(
|
|||
shop_interaction: ShopInteractionType,
|
||||
storage_interaction: PlayerStorageInteractionType,
|
||||
decor_shop_interaction: DecorShopInteractionType,
|
||||
rv_upgrade_shop_interaction: RVUpgradeInteractionType,
|
||||
) -> void:
|
||||
_shop_interaction = shop_interaction
|
||||
_storage_interaction = storage_interaction
|
||||
_decor_shop_interaction = decor_shop_interaction
|
||||
_rv_upgrade_shop_interaction = rv_upgrade_shop_interaction
|
||||
_fishing_shop.set_world_interaction(shop_interaction)
|
||||
_player_storage.set_world_interaction(storage_interaction)
|
||||
_decor_shop.set_world_interaction(decor_shop_interaction)
|
||||
_rv_upgrade_shop.set_world_interaction(rv_upgrade_shop_interaction)
|
||||
|
||||
|
||||
func _prioritize_surface_drawing_pointer_input() -> void:
|
||||
|
|
@ -1539,6 +1568,13 @@ func _process(delta: float) -> void:
|
|||
_update_virtual_mouse(delta)
|
||||
_update_controller_menu_scroll(delta)
|
||||
_update_experience_bubble_position()
|
||||
_update_fishing_danger_vignette(delta)
|
||||
_try_start_shop_npc_speech()
|
||||
if _player != null:
|
||||
_player.set_fishing_reel_camera_active(
|
||||
_fishing_spot != null
|
||||
and _fishing_spot.is_reel_input_active()
|
||||
)
|
||||
|
||||
|
||||
func _update_controller_menu_scroll(delta: float) -> void:
|
||||
|
|
@ -1793,6 +1829,7 @@ func set_gameplay_ui_enabled(enabled: bool) -> void:
|
|||
close_player_menu_for_session_end()
|
||||
_fishing_shop.close_for_session_end()
|
||||
_decor_shop.close_for_session_end()
|
||||
_rv_upgrade_shop.close_for_session_end()
|
||||
_player_storage.close_for_session_end()
|
||||
_fishing_panel.visible = false
|
||||
_shop_prompt.hide()
|
||||
|
|
@ -1933,6 +1970,10 @@ func get_decor_shop() -> DecorShopType:
|
|||
return _decor_shop
|
||||
|
||||
|
||||
func get_rv_upgrade_shop() -> RVUpgradeShopType:
|
||||
return _rv_upgrade_shop
|
||||
|
||||
|
||||
func get_player_storage() -> PlayerStorageType:
|
||||
return _player_storage
|
||||
|
||||
|
|
@ -2027,8 +2068,19 @@ func set_shop_prompt_visible(
|
|||
_position_shop_prompt(world_anchor)
|
||||
|
||||
|
||||
func set_shop_npc_player_in_range(in_range: bool) -> void:
|
||||
if _shop_npc_player_in_range == in_range:
|
||||
func set_shop_npc_player_in_range(
|
||||
in_range: bool,
|
||||
dialogue_text: String = "",
|
||||
) -> void:
|
||||
var dialogue_changed: bool = (
|
||||
not dialogue_text.is_empty()
|
||||
and _shop_prompt_message.text != dialogue_text
|
||||
)
|
||||
if dialogue_changed:
|
||||
_shop_prompt_message.text = dialogue_text
|
||||
_shop_prompt_message.visible_characters = -1
|
||||
_shop_npc_spoken_for_current_visit = false
|
||||
if _shop_npc_player_in_range == in_range and not dialogue_changed:
|
||||
return
|
||||
_shop_npc_player_in_range = in_range
|
||||
if not in_range:
|
||||
|
|
@ -2044,10 +2096,10 @@ func _try_start_shop_npc_speech() -> void:
|
|||
or not _gameplay_ui_enabled
|
||||
):
|
||||
return
|
||||
_shop_npc_spoken_for_current_visit = true
|
||||
var now_msec: int = Time.get_ticks_msec()
|
||||
if now_msec < _shop_npc_next_speech_msec:
|
||||
return
|
||||
_shop_npc_spoken_for_current_visit = true
|
||||
_shop_npc_next_speech_msec = (
|
||||
now_msec + SHOP_NPC_SPEECH_COOLDOWN_MILLISECONDS
|
||||
)
|
||||
|
|
@ -2310,6 +2362,12 @@ func _on_catch_display_changed(
|
|||
and _fishing_spot != null
|
||||
and _fishing_spot.is_fighting()
|
||||
)
|
||||
_update_fishing_feedback(
|
||||
progress,
|
||||
chase_progress,
|
||||
barrier_health,
|
||||
encounter_visible,
|
||||
)
|
||||
_green_catch_progress.value = progress * 100.0
|
||||
_red_chase_progress.value = maxf(chase_progress, 0.0) * 100.0
|
||||
_catch_track.visible = encounter_visible
|
||||
|
|
@ -2346,6 +2404,93 @@ func _on_catch_display_changed(
|
|||
_refresh_fishing_panel_visibility()
|
||||
|
||||
|
||||
func _update_fishing_feedback(
|
||||
progress: float,
|
||||
chase_progress: float,
|
||||
barrier_health: PackedInt32Array,
|
||||
encounter_visible: bool,
|
||||
) -> void:
|
||||
if not encounter_visible:
|
||||
_previous_barrier_health.clear()
|
||||
_barrier_feedback_initialized = false
|
||||
_fishing_danger_target = 0.0
|
||||
return
|
||||
if _barrier_feedback_initialized:
|
||||
var comparison_count: int = mini(
|
||||
_previous_barrier_health.size(),
|
||||
barrier_health.size(),
|
||||
)
|
||||
var barrier_hit: bool = false
|
||||
var barrier_broken: bool = false
|
||||
for barrier_index: int in range(comparison_count):
|
||||
if (
|
||||
barrier_health[barrier_index]
|
||||
>= _previous_barrier_health[barrier_index]
|
||||
):
|
||||
continue
|
||||
barrier_hit = true
|
||||
barrier_broken = (
|
||||
barrier_broken
|
||||
or barrier_health[barrier_index] <= 0
|
||||
)
|
||||
if barrier_hit:
|
||||
_play_barrier_feedback(barrier_broken)
|
||||
_previous_barrier_health = barrier_health.duplicate()
|
||||
_barrier_feedback_initialized = true
|
||||
var chase_gap: float = progress - maxf(chase_progress, 0.0)
|
||||
_fishing_danger_target = clampf(
|
||||
inverse_lerp(
|
||||
FISHING_DANGER_START_GAP,
|
||||
FISHING_DANGER_FULL_GAP,
|
||||
chase_gap,
|
||||
),
|
||||
0.0,
|
||||
1.0,
|
||||
)
|
||||
|
||||
|
||||
func _play_barrier_feedback(barrier_broken: bool) -> void:
|
||||
if _player != null:
|
||||
_player.play_fishing_barrier_camera_feedback(barrier_broken)
|
||||
if _catch_track_shake_tween != null:
|
||||
_catch_track_shake_tween.kill()
|
||||
_catch_track.rotation = 0.0
|
||||
var tilt: float = 0.018 if barrier_broken else 0.008
|
||||
var beat: float = 0.038 if barrier_broken else 0.028
|
||||
_catch_track_shake_tween = create_tween()
|
||||
_catch_track_shake_tween.tween_property(
|
||||
_catch_track, "rotation", -tilt, beat
|
||||
)
|
||||
_catch_track_shake_tween.tween_property(
|
||||
_catch_track, "rotation", tilt, beat
|
||||
)
|
||||
_catch_track_shake_tween.tween_property(
|
||||
_catch_track, "rotation", -tilt * 0.45, beat
|
||||
)
|
||||
_catch_track_shake_tween.tween_property(
|
||||
_catch_track, "rotation", 0.0, beat
|
||||
)
|
||||
|
||||
|
||||
func _update_fishing_danger_vignette(delta: float) -> void:
|
||||
_fishing_danger_pulse_time += delta
|
||||
_fishing_danger_intensity = lerpf(
|
||||
_fishing_danger_intensity,
|
||||
_fishing_danger_target,
|
||||
1.0 - exp(-8.0 * delta),
|
||||
)
|
||||
var pulse: float = (
|
||||
0.88 + sin(_fishing_danger_pulse_time * 5.5) * 0.12
|
||||
)
|
||||
var shown_intensity: float = _fishing_danger_intensity * pulse
|
||||
_fishing_danger_vignette.visible = shown_intensity > 0.01
|
||||
var vignette_material := (
|
||||
_fishing_danger_vignette.material as ShaderMaterial
|
||||
)
|
||||
if vignette_material != null:
|
||||
vignette_material.set_shader_parameter("intensity", shown_intensity)
|
||||
|
||||
|
||||
func _update_barrier_markers(
|
||||
positions: PackedFloat32Array,
|
||||
health: PackedInt32Array,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
[gd_scene load_steps=24 format=3]
|
||||
[gd_scene load_steps=27 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://ui/game_ui.gd" id="1_ui"]
|
||||
[ext_resource type="PackedScene" path="res://ui/player_menu.tscn" id="2_menu"]
|
||||
|
|
@ -17,6 +17,11 @@
|
|||
[ext_resource type="PackedScene" path="res://ui/components/bubble_menu/bubble_confirmation_page.tscn" id="15_social_prompt"]
|
||||
[ext_resource type="PackedScene" path="res://ui/decor_shop.tscn" id="16_decor_shop"]
|
||||
[ext_resource type="PackedScene" path="res://ui/home_decor_toolbar.tscn" id="17_decor_toolbar"]
|
||||
[ext_resource type="PackedScene" path="res://ui/rv_upgrade_shop.tscn" id="18_rv_upgrade_shop"]
|
||||
[ext_resource type="Shader" path="res://ui/fishing_danger_vignette.gdshader" id="19_fishing_vignette"]
|
||||
|
||||
[sub_resource type="ShaderMaterial" id="ShaderMaterial_fishing_vignette"]
|
||||
shader = ExtResource("19_fishing_vignette")
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBox_chase_background"]
|
||||
bg_color = Color(0.032, 0.118, 0.15, 1)
|
||||
|
|
@ -86,6 +91,20 @@ grow_horizontal = 2
|
|||
grow_vertical = 2
|
||||
mouse_filter = 2
|
||||
|
||||
[node name="FishingDangerVignette" type="ColorRect" parent="UIRoot/CanonicalStage/GameplayTransientHUD"]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
z_index = 50
|
||||
layout_mode = 1
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
mouse_filter = 2
|
||||
material = SubResource("ShaderMaterial_fishing_vignette")
|
||||
color = Color(1, 1, 1, 1)
|
||||
|
||||
[node name="ActiveBaitIndicator" type="Control" parent="UIRoot/CanonicalStage/GameplayTransientHUD"]
|
||||
unique_name_in_owner = true
|
||||
z_index = 54
|
||||
|
|
@ -312,6 +331,7 @@ offset_right = 420.0
|
|||
offset_bottom = -124.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 0
|
||||
pivot_offset = Vector2(420, 18)
|
||||
mouse_filter = 2
|
||||
|
||||
[node name="GreenCatchProgress" type="ProgressBar" parent="UIRoot/CanonicalStage/GameplayTransientHUD/CatchTrack"]
|
||||
|
|
@ -440,7 +460,7 @@ theme_override_constants/margin_bottom = 8
|
|||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
theme_override_font_sizes/font_size = 18
|
||||
text = "Hey, if you've got any fish I've got cash! OwO"
|
||||
text = "Listen, you may suck at fishing but I've got some things that might help."
|
||||
horizontal_alignment = 1
|
||||
vertical_alignment = 1
|
||||
autowrap_mode = 2
|
||||
|
|
@ -477,6 +497,9 @@ unique_name_in_owner = true
|
|||
[node name="DecorShop" parent="UIRoot/CanonicalStage" instance=ExtResource("16_decor_shop")]
|
||||
unique_name_in_owner = true
|
||||
|
||||
[node name="RVUpgradeShop" parent="UIRoot/CanonicalStage" instance=ExtResource("18_rv_upgrade_shop")]
|
||||
unique_name_in_owner = true
|
||||
|
||||
[node name="HomeDecorToolbar" parent="UIRoot/CanonicalStage" instance=ExtResource("17_decor_toolbar")]
|
||||
unique_name_in_owner = true
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,10 @@ var _mode_button: Button
|
|||
var _selection_label: Label
|
||||
var _rotate_button: Button
|
||||
var _store_button: Button
|
||||
var _clear_button: Button
|
||||
var _mode: PlayerHomeState.PlacementMode = PlayerHomeState.PlacementMode.GRID
|
||||
var _interactive: bool = true
|
||||
var _selection_active: bool = false
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
|
|
@ -22,31 +25,33 @@ func set_active(active: bool) -> void:
|
|||
if visible == active:
|
||||
return
|
||||
visible = active
|
||||
if active and _mode_button != null:
|
||||
_mode_button.call_deferred("grab_focus")
|
||||
|
||||
|
||||
func set_interactive(interactive: bool) -> void:
|
||||
_interactive = interactive
|
||||
_refresh_button_interactivity()
|
||||
|
||||
|
||||
func set_mode(mode: PlayerHomeState.PlacementMode) -> void:
|
||||
_mode = mode
|
||||
if _mode_button != null:
|
||||
_mode_button.text = (
|
||||
"placement: grid"
|
||||
"grid"
|
||||
if mode == PlayerHomeState.PlacementMode.GRID
|
||||
else "placement: free"
|
||||
else "free"
|
||||
)
|
||||
_mode_button.tooltip_text = "placement mode: %s" % _mode_button.text
|
||||
|
||||
|
||||
func set_selection(instance_id: String, display_name: String = "") -> void:
|
||||
var selected: bool = not instance_id.is_empty()
|
||||
_selection_active = selected
|
||||
if _selection_label != null:
|
||||
_selection_label.text = (
|
||||
"selected: %s" % display_name
|
||||
if selected else "click decor to select; drag to move"
|
||||
if selected else "use held decor to place; click or drag to edit"
|
||||
)
|
||||
if _rotate_button != null:
|
||||
_rotate_button.disabled = not selected
|
||||
if _store_button != null:
|
||||
_store_button.disabled = not selected
|
||||
_refresh_button_interactivity()
|
||||
|
||||
|
||||
func report_status(message: String) -> void:
|
||||
|
|
@ -55,65 +60,92 @@ func report_status(message: String) -> void:
|
|||
|
||||
|
||||
func _build_ui() -> void:
|
||||
custom_minimum_size = Vector2(330.0, 0.0)
|
||||
position = Vector2(925.0, 540.0)
|
||||
z_index = 58
|
||||
set_anchors_preset(Control.PRESET_TOP_RIGHT)
|
||||
offset_left = -500.0
|
||||
offset_top = 0.0
|
||||
offset_right = 0.0
|
||||
offset_bottom = 106.0
|
||||
custom_minimum_size = Vector2(500.0, 0.0)
|
||||
z_index = 85
|
||||
mouse_filter = Control.MOUSE_FILTER_STOP
|
||||
add_theme_stylebox_override(
|
||||
"panel",
|
||||
UtilityPageStyle.rounded_style(
|
||||
Color(UtilityPageStyle.OCEAN_PANEL_DEEP, 0.96), 16
|
||||
),
|
||||
)
|
||||
var panel_style: StyleBoxFlat = UtilityPageStyle.panel_style()
|
||||
panel_style.set_corner_radius_all(10)
|
||||
panel_style.content_margin_left = 6.0
|
||||
panel_style.content_margin_top = 6.0
|
||||
panel_style.content_margin_right = 6.0
|
||||
panel_style.content_margin_bottom = 6.0
|
||||
add_theme_stylebox_override("panel", panel_style)
|
||||
var margin := MarginContainer.new()
|
||||
for side: StringName in [
|
||||
&"margin_left", &"margin_top", &"margin_right", &"margin_bottom",
|
||||
]:
|
||||
margin.add_theme_constant_override(side, 12)
|
||||
margin.add_theme_constant_override(side, 6)
|
||||
add_child(margin)
|
||||
var layout := VBoxContainer.new()
|
||||
layout.add_theme_constant_override("separation", 8)
|
||||
layout.add_theme_constant_override("separation", 5)
|
||||
margin.add_child(layout)
|
||||
var title := Label.new()
|
||||
title.text = "RV decor"
|
||||
title.add_theme_font_size_override("font_size", 24)
|
||||
layout.add_child(title)
|
||||
_selection_label = Label.new()
|
||||
_selection_label.text = "click decor to select; drag to move"
|
||||
_selection_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||
_selection_label.add_theme_font_size_override("font_size", 17)
|
||||
layout.add_child(_selection_label)
|
||||
var row := HBoxContainer.new()
|
||||
row.add_theme_constant_override("separation", 8)
|
||||
row.add_theme_constant_override("separation", 5)
|
||||
layout.add_child(row)
|
||||
_mode_button = Button.new()
|
||||
_mode_button.text = "placement: grid"
|
||||
_mode_button.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
UtilityPageStyle.apply_ocean_button(_mode_button)
|
||||
var title := Label.new()
|
||||
title.text = "decor"
|
||||
title.custom_minimum_size = Vector2(70.0, 46.0)
|
||||
title.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
|
||||
title.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
title.add_theme_font_size_override("font_size", 19)
|
||||
row.add_child(title)
|
||||
_mode_button = _add_tool_button(row, "grid", "switch placement mode", 82.0)
|
||||
_mode_button.pressed.connect(_toggle_mode)
|
||||
row.add_child(_mode_button)
|
||||
_rotate_button = Button.new()
|
||||
_rotate_button.text = "rotate"
|
||||
_rotate_button.disabled = true
|
||||
UtilityPageStyle.apply_ocean_button(_rotate_button)
|
||||
_rotate_button = _add_tool_button(row, "rotate", "rotate selected decor", 92.0)
|
||||
_rotate_button.pressed.connect(rotate_requested.emit)
|
||||
row.add_child(_rotate_button)
|
||||
var action_row := HBoxContainer.new()
|
||||
action_row.add_theme_constant_override("separation", 8)
|
||||
layout.add_child(action_row)
|
||||
_store_button = Button.new()
|
||||
_store_button.text = "pack up"
|
||||
_store_button.disabled = true
|
||||
_store_button.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
UtilityPageStyle.apply_ocean_button(_store_button)
|
||||
_store_button = _add_tool_button(row, "pack", "pack selected decor", 82.0)
|
||||
_store_button.pressed.connect(store_requested.emit)
|
||||
action_row.add_child(_store_button)
|
||||
var cancel_button := Button.new()
|
||||
cancel_button.text = "clear selection"
|
||||
cancel_button.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
UtilityPageStyle.apply_ocean_button(cancel_button)
|
||||
cancel_button.pressed.connect(cancel_requested.emit)
|
||||
action_row.add_child(cancel_button)
|
||||
_clear_button = _add_tool_button(row, "clear", "clear selection", 82.0)
|
||||
_clear_button.pressed.connect(cancel_requested.emit)
|
||||
_selection_label = Label.new()
|
||||
_selection_label.text = "use held decor to place; click or drag to edit"
|
||||
_selection_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||
_selection_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
_selection_label.add_theme_font_size_override("font_size", 15)
|
||||
layout.add_child(_selection_label)
|
||||
_refresh_button_interactivity()
|
||||
|
||||
|
||||
func _add_tool_button(
|
||||
parent: Container,
|
||||
button_text: String,
|
||||
button_tooltip: String,
|
||||
minimum_width: float,
|
||||
) -> Button:
|
||||
var button := Button.new()
|
||||
button.text = button_text
|
||||
button.tooltip_text = button_tooltip
|
||||
button.accessibility_name = button_tooltip
|
||||
button.custom_minimum_size = Vector2(minimum_width, 46.0)
|
||||
button.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
UtilityPageStyle.apply_ocean_button(button)
|
||||
for style_name: StringName in [
|
||||
&"normal", &"hover", &"pressed", &"focus", &"disabled",
|
||||
]:
|
||||
var existing: StyleBox = button.get_theme_stylebox(style_name)
|
||||
var rounded := existing.duplicate() as StyleBoxFlat
|
||||
if rounded == null:
|
||||
continue
|
||||
rounded.set_corner_radius_all(20)
|
||||
button.add_theme_stylebox_override(style_name, rounded)
|
||||
parent.add_child(button)
|
||||
return button
|
||||
|
||||
|
||||
func _refresh_button_interactivity() -> void:
|
||||
if _mode_button != null:
|
||||
_mode_button.disabled = not _interactive
|
||||
if _rotate_button != null:
|
||||
_rotate_button.disabled = not _interactive or not _selection_active
|
||||
if _store_button != null:
|
||||
_store_button.disabled = not _interactive or not _selection_active
|
||||
if _clear_button != null:
|
||||
_clear_button.disabled = not _interactive or not _selection_active
|
||||
|
||||
|
||||
func _toggle_mode() -> void:
|
||||
|
|
|
|||
|
|
@ -2575,7 +2575,10 @@ func _on_tackle_button_gui_input(
|
|||
call_deferred("_release_pointer_focus", button)
|
||||
if (
|
||||
mouse_event == null
|
||||
or mouse_event.button_index != MOUSE_BUTTON_RIGHT
|
||||
or mouse_event.button_index not in [
|
||||
MOUSE_BUTTON_LEFT,
|
||||
MOUSE_BUTTON_RIGHT,
|
||||
]
|
||||
or not mouse_event.pressed
|
||||
):
|
||||
return
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ func _open_storage(
|
|||
):
|
||||
return false
|
||||
_home_access = home_access
|
||||
_title.text = "RV storage" if home_access else "private storage"
|
||||
_title.text = "home storage" if home_access else "private storage"
|
||||
_decorate_button.visible = home_access and allow_decorating
|
||||
_prior_movement_enabled = _player.is_movement_enabled()
|
||||
_prior_camera_enabled = _player.is_camera_input_enabled()
|
||||
|
|
@ -290,8 +290,8 @@ func _build_ui() -> void:
|
|||
_title.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
header.add_child(_title)
|
||||
_decorate_button = Button.new()
|
||||
_decorate_button.text = "decorate RV"
|
||||
_decorate_button.tooltip_text = "Place decor inside your RV"
|
||||
_decorate_button.text = "decorate home"
|
||||
_decorate_button.tooltip_text = "Place decor inside your home"
|
||||
_decorate_button.custom_minimum_size = Vector2(160.0, 48.0)
|
||||
UtilityPageStyle.apply_ocean_button(_decorate_button)
|
||||
_decorate_button.hide()
|
||||
|
|
|
|||
330
ui/rv_upgrade_shop.gd
Normal file
330
ui/rv_upgrade_shop.gd
Normal file
|
|
@ -0,0 +1,330 @@
|
|||
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
|
||||
)
|
||||
1
ui/rv_upgrade_shop.gd.uid
Normal file
1
ui/rv_upgrade_shop.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://b5pnsuph7fxrd
|
||||
14
ui/rv_upgrade_shop.tscn
Normal file
14
ui/rv_upgrade_shop.tscn
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
[gd_scene load_steps=2 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://ui/rv_upgrade_shop.gd" id="1_script"]
|
||||
|
||||
[node name="RVUpgradeShop" type="Control"]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
layout_mode = 3
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
script = ExtResource("1_script")
|
||||
Loading…
Add table
Add a link
Reference in a new issue