Compare commits
No commits in common. "7c8cc9276ee99cfadc4d57a24ed104d55e5a9433" and "9cd09ffe47acfdd850e99ede32ec40aebee5e23a" have entirely different histories.
7c8cc9276e
...
9cd09ffe47
29 changed files with 86 additions and 783 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -6,8 +6,6 @@ const ItemDataType = preload("res://items/item_data.gd")
|
|||
const PlayerBagType = preload("res://inventory/player_bag.gd")
|
||||
const PlayerWalletType = preload("res://economy/player_wallet.gd")
|
||||
const WORM_MAX_STACK: int = 10
|
||||
const FISH_FINDER_ID: StringName = &"fish_finder"
|
||||
const BATTERIES_ID: StringName = &"batteries"
|
||||
|
||||
const ITEM_PRICES: Dictionary[StringName, int] = {
|
||||
&"worms": 1,
|
||||
|
|
@ -17,12 +15,10 @@ const ITEM_PRICES: Dictionary[StringName, int] = {
|
|||
&"whole_anchovy": 30,
|
||||
&"whole_sardine": 60,
|
||||
&"luminous_roe": 125,
|
||||
&"the_standby": 750,
|
||||
&"coffee": 20,
|
||||
&"energy_drink": 35,
|
||||
&"snack": 30,
|
||||
FISH_FINDER_ID: 500,
|
||||
BATTERIES_ID: 15,
|
||||
&"fish_finder": 60,
|
||||
}
|
||||
const BAIT_UNLOCK_PRICES: Dictionary[StringName, int] = {
|
||||
&"snails": 400,
|
||||
|
|
@ -40,12 +36,10 @@ const ITEM_ORDER: Array[StringName] = [
|
|||
&"whole_anchovy",
|
||||
&"whole_sardine",
|
||||
&"luminous_roe",
|
||||
&"the_standby",
|
||||
FISH_FINDER_ID,
|
||||
&"coffee",
|
||||
&"energy_drink",
|
||||
&"snack",
|
||||
BATTERIES_ID,
|
||||
&"fish_finder",
|
||||
]
|
||||
|
||||
|
||||
|
|
@ -75,20 +69,6 @@ static func is_bait_topoff(item_id: StringName) -> bool:
|
|||
return item_id == &"worms" or BAIT_UNLOCK_PRICES.has(item_id)
|
||||
|
||||
|
||||
static func is_permanent_unlock(
|
||||
item_id: StringName,
|
||||
item: ItemDataType,
|
||||
) -> bool:
|
||||
return (
|
||||
item != null
|
||||
and (item.is_lure() or item_id == FISH_FINDER_ID)
|
||||
)
|
||||
|
||||
|
||||
static func is_passive_supply(item_id: StringName) -> bool:
|
||||
return item_id == BATTERIES_ID
|
||||
|
||||
|
||||
static func get_purchase_cost(
|
||||
item_id: StringName,
|
||||
quantity: int,
|
||||
|
|
@ -112,7 +92,6 @@ static func purchase_one(
|
|||
return false
|
||||
var item: ItemDataType = catalog.get_item_by_id(item_id)
|
||||
var bait_topoff: bool = is_bait_topoff(item_id)
|
||||
var permanent_unlock: bool = is_permanent_unlock(item_id, item)
|
||||
var quantity: int = get_purchase_quantity(
|
||||
item_id,
|
||||
bag.get_quantity(item_id),
|
||||
|
|
@ -127,18 +106,9 @@ static func purchase_one(
|
|||
price < 0
|
||||
or item == null
|
||||
or not item.is_valid()
|
||||
or (
|
||||
item.category != ItemDataType.Category.CONSUMABLE
|
||||
and not bait_topoff
|
||||
and not permanent_unlock
|
||||
)
|
||||
or (not item.stackable and not permanent_unlock)
|
||||
or (
|
||||
not item.usable
|
||||
and not bait_topoff
|
||||
and not permanent_unlock
|
||||
and not is_passive_supply(item_id)
|
||||
)
|
||||
or (item.category != ItemDataType.Category.CONSUMABLE and not bait_topoff)
|
||||
or not item.stackable
|
||||
or (not item.usable and not bait_topoff)
|
||||
or not bag.can_add_item(item_id, quantity)
|
||||
or not wallet.can_afford(price)
|
||||
):
|
||||
|
|
|
|||
|
|
@ -19,8 +19,8 @@ const WORM_ROLL_WEIGHTS: Array[float] = [80.0, 10.0, 5.0, 4.0, 1.0]
|
|||
const SNAIL_ROLL_WEIGHTS: Array[float] = [68.0, 16.0, 8.0, 6.0, 2.0]
|
||||
const SHRIMP_ROLL_WEIGHTS: Array[float] = [56.0, 21.0, 12.0, 8.0, 3.0]
|
||||
const SQUID_ROLL_WEIGHTS: Array[float] = [44.0, 25.0, 16.0, 11.0, 4.0]
|
||||
const SARDINE_ROLL_WEIGHTS: Array[float] = [34.0, 27.0, 20.0, 13.0, 6.0]
|
||||
const MINNOW_ROLL_WEIGHTS: Array[float] = [25.0, 28.0, 23.0, 16.0, 8.0]
|
||||
const ANCHOVY_ROLL_WEIGHTS: Array[float] = [34.0, 27.0, 20.0, 13.0, 6.0]
|
||||
const SARDINE_ROLL_WEIGHTS: Array[float] = [25.0, 28.0, 23.0, 16.0, 8.0]
|
||||
const LUMINOUS_ROE_ROLL_WEIGHTS: Array[float] = [16.0, 26.0, 26.0, 20.0, 12.0]
|
||||
const SALE_MULTIPLIERS: Array[float] = [1.0, 1.1, 1.25, 1.5, 2.0]
|
||||
# Legacy profile multiplier retained for serialized/profile compatibility.
|
||||
|
|
@ -158,9 +158,9 @@ static func rarity_weights_for_bait(
|
|||
elif active_bait_tags.has(&"bait_rarity_6"):
|
||||
weights.assign(LUMINOUS_ROE_ROLL_WEIGHTS)
|
||||
elif active_bait_tags.has(&"bait_rarity_5"):
|
||||
weights.assign(MINNOW_ROLL_WEIGHTS)
|
||||
elif active_bait_tags.has(&"bait_rarity_4"):
|
||||
weights.assign(SARDINE_ROLL_WEIGHTS)
|
||||
elif active_bait_tags.has(&"bait_rarity_4"):
|
||||
weights.assign(ANCHOVY_ROLL_WEIGHTS)
|
||||
elif active_bait_tags.has(&"bait_rarity_3"):
|
||||
weights.assign(SQUID_ROLL_WEIGHTS)
|
||||
elif active_bait_tags.has(&"bait_rarity_2"):
|
||||
|
|
|
|||
|
|
@ -47,7 +47,6 @@ const WorldWeatherServiceType = preload(
|
|||
)
|
||||
|
||||
signal status_changed(status: String)
|
||||
signal local_speech_requested(message: String)
|
||||
signal catch_display_changed(
|
||||
progress: float,
|
||||
chase_progress: float,
|
||||
|
|
@ -65,7 +64,6 @@ signal showcase_changed(
|
|||
visible: bool,
|
||||
)
|
||||
signal bite_activated
|
||||
signal bite_prompt_changed(is_visible: bool)
|
||||
signal ready_for_equipment_refresh
|
||||
signal fish_showcase_toggle_requested
|
||||
signal art_ui_toggle_requested
|
||||
|
|
@ -177,8 +175,6 @@ var _network_auto_click_accumulator: float = 0.0
|
|||
var _network_active_barrier_index: int = -1
|
||||
var _bite_rng: RandomNumberGenerator = RandomNumberGenerator.new()
|
||||
var _pending_cleanup_message: String = ""
|
||||
var _bite_confirmation_pending: bool = false
|
||||
var _bite_confirmation_requested: bool = false
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
|
|
@ -255,9 +251,6 @@ func setup(
|
|||
_network_fishing.local_bite_started.connect(
|
||||
_on_network_bite_started
|
||||
)
|
||||
_network_fishing.local_bite_pending.connect(
|
||||
_on_network_bite_pending
|
||||
)
|
||||
_network_fishing.local_snapshot_received.connect(
|
||||
_on_network_fishing_snapshot
|
||||
)
|
||||
|
|
@ -521,25 +514,14 @@ func _unhandled_input(event: InputEvent) -> void:
|
|||
return
|
||||
if (
|
||||
active_item != null
|
||||
and (
|
||||
active_item.category == ItemDataType.Category.CONSUMABLE
|
||||
or (
|
||||
active_item.item_id == PlayerItemEffectsType.FISH_FINDER_ID
|
||||
)
|
||||
)
|
||||
and active_item.category == ItemDataType.Category.CONSUMABLE
|
||||
):
|
||||
if _network_item_use != null:
|
||||
_network_item_use.request_use(active_item.item_id)
|
||||
elif _item_effects.use_item(active_item, _local_bag):
|
||||
elif _item_effects.use_consumable(active_item, _local_bag):
|
||||
status_changed.emit(_item_effects.get_feedback(
|
||||
active_item.item_id
|
||||
))
|
||||
elif (
|
||||
active_item.item_id == PlayerItemEffectsType.FISH_FINDER_ID
|
||||
):
|
||||
local_speech_requested.emit(
|
||||
PlayerItemEffectsType.FISH_FINDER_DEAD_MESSAGE
|
||||
)
|
||||
get_viewport().set_input_as_handled()
|
||||
return
|
||||
if not has_active_fishing_rod():
|
||||
|
|
@ -570,10 +552,6 @@ func _unhandled_input(event: InputEvent) -> void:
|
|||
else:
|
||||
return
|
||||
FishingState.WAITING_FOR_BITE:
|
||||
if _bite_confirmation_pending:
|
||||
confirm_pending_bite()
|
||||
get_viewport().set_input_as_handled()
|
||||
return
|
||||
_withdrawal_input_held = true
|
||||
_start_reeling_audio()
|
||||
if _network_fishing != null:
|
||||
|
|
@ -590,9 +568,6 @@ func _unhandled_input(event: InputEvent) -> void:
|
|||
_confirm_cast()
|
||||
get_viewport().set_input_as_handled()
|
||||
elif state == FishingState.WAITING_FOR_BITE:
|
||||
if _bite_confirmation_pending:
|
||||
get_viewport().set_input_as_handled()
|
||||
return
|
||||
_withdrawal_input_held = false
|
||||
_stop_reeling_audio()
|
||||
if _network_fishing != null:
|
||||
|
|
@ -707,28 +682,6 @@ func is_fighting() -> bool:
|
|||
return state == FishingState.FIGHTING
|
||||
|
||||
|
||||
func confirm_pending_bite() -> void:
|
||||
if state != FishingState.WAITING_FOR_BITE or not _bite_confirmation_pending:
|
||||
return
|
||||
_bite_confirmation_requested = true
|
||||
if _network_fishing != null:
|
||||
_network_primary_input_held = false
|
||||
_network_input_resend_elapsed = 0.0
|
||||
_network_fishing.submit_local_input(false, true)
|
||||
else:
|
||||
_activate_bite(true)
|
||||
|
||||
|
||||
func _set_bite_confirmation_pending(is_pending: bool) -> void:
|
||||
if _bite_confirmation_pending == is_pending:
|
||||
if not is_pending:
|
||||
_bite_confirmation_requested = false
|
||||
return
|
||||
_bite_confirmation_pending = is_pending
|
||||
_bite_confirmation_requested = false
|
||||
bite_prompt_changed.emit(is_pending)
|
||||
|
||||
|
||||
func is_returning() -> bool:
|
||||
return state == FishingState.RETURNING
|
||||
|
||||
|
|
@ -838,7 +791,6 @@ func _on_cast_completed() -> void:
|
|||
_consume_active_bait()
|
||||
|
||||
state = FishingState.WAITING_FOR_BITE
|
||||
_active_player.set_fishing_visual(true)
|
||||
_state_time_remaining = roll_bite_wait_time() * (
|
||||
_item_effects.get_bite_time_multiplier()
|
||||
if _item_effects != null
|
||||
|
|
@ -893,8 +845,6 @@ func roll_bite_wait_time() -> float:
|
|||
|
||||
|
||||
func _update_waiting_for_bite(delta: float) -> void:
|
||||
if _bite_confirmation_pending:
|
||||
return
|
||||
if (
|
||||
_withdrawal_input_held
|
||||
and not Input.is_action_pressed("fish_primary")
|
||||
|
|
@ -989,7 +939,7 @@ func _get_withdrawable_distance() -> float:
|
|||
return landing_offset.length() - withdrawal_cancel_distance
|
||||
|
||||
|
||||
func _activate_bite(confirmation_override: bool = false) -> void:
|
||||
func _activate_bite() -> void:
|
||||
if state != FishingState.WAITING_FOR_BITE:
|
||||
return
|
||||
|
||||
|
|
@ -1001,19 +951,7 @@ func _activate_bite(confirmation_override: bool = false) -> void:
|
|||
):
|
||||
_cancel_attempt()
|
||||
return
|
||||
if (
|
||||
not confirmation_override
|
||||
and _active_lure_has_effect(&"deferred_fight")
|
||||
):
|
||||
_state_time_remaining = 0.0
|
||||
_withdrawal_input_held = false
|
||||
_set_bite_confirmation_pending(true)
|
||||
status_changed.emit("")
|
||||
_presentation.set_line_mode(FishingPresentationType.LineMode.TAUT)
|
||||
_presentation.show_bite()
|
||||
return
|
||||
|
||||
_set_bite_confirmation_pending(false)
|
||||
state = FishingState.FIGHTING
|
||||
_active_player.set_fighting_visual(true)
|
||||
_state_time_remaining = 0.0
|
||||
|
|
@ -1105,7 +1043,6 @@ func _on_catch_completed() -> void:
|
|||
return
|
||||
_stop_fight_audio()
|
||||
_active_player.set_fighting_visual(false)
|
||||
_active_player.set_fishing_visual(false)
|
||||
state = FishingState.SHOWING_CATCH
|
||||
_showcase_ready = false
|
||||
_showcase_outcome_completed = false
|
||||
|
|
@ -1226,12 +1163,10 @@ func _cleanup_attempt(
|
|||
cooldown_message: String = "",
|
||||
visual_outcome: StringName = &"",
|
||||
) -> void:
|
||||
_set_bite_confirmation_pending(false)
|
||||
_stop_fight_audio()
|
||||
_stop_reeling_audio()
|
||||
if _active_player != null:
|
||||
_active_player.set_fighting_visual(false)
|
||||
_active_player.set_fishing_visual(false)
|
||||
if not visual_outcome.is_empty():
|
||||
if state == FishingState.RETURNING:
|
||||
return
|
||||
|
|
@ -1261,7 +1196,6 @@ func _finalize_attempt_cleanup(cooldown_message: String) -> void:
|
|||
_showcase_restore_generation += 1
|
||||
if _active_player != null:
|
||||
_active_player.set_fighting_visual(false)
|
||||
_active_player.set_fishing_visual(false)
|
||||
_active_player.end_catch_showcase()
|
||||
_active_player.set_movement_enabled(true)
|
||||
_active_player = null
|
||||
|
|
@ -1476,21 +1410,6 @@ func _get_active_bait_tags() -> Array[StringName]:
|
|||
return item.bait_tags.duplicate() if item != null and item.is_bait() else []
|
||||
|
||||
|
||||
func _active_lure_has_effect(effect_id: StringName) -> bool:
|
||||
if (
|
||||
_local_player == null
|
||||
or _item_catalog == null
|
||||
or _local_bag == null
|
||||
or _local_player.active_lure_id.is_empty()
|
||||
or not _local_bag.owns_item(_local_player.active_lure_id)
|
||||
):
|
||||
return false
|
||||
var lure: ItemDataType = _item_catalog.get_item_by_id(
|
||||
_local_player.active_lure_id
|
||||
)
|
||||
return lure != null and lure.is_lure() and effect_id in lure.lure_effects
|
||||
|
||||
|
||||
func _build_network_evidence() -> Dictionary:
|
||||
var rarity_multipliers: Array[float] = []
|
||||
for rarity: int in range(FishDataType.Rarity.size()):
|
||||
|
|
@ -1502,7 +1421,6 @@ func _build_network_evidence() -> Dictionary:
|
|||
var item: ItemDataType = _get_active_item()
|
||||
return {
|
||||
"bait_id": str(_active_player.active_bait_id),
|
||||
"lure_id": str(_active_player.active_lure_id),
|
||||
"rod_id": str(item.item_id) if item != null else "",
|
||||
"reel_speed": _active_player.reel_speed * (
|
||||
_fishing_upgrades.get_reel_speed_multiplier()
|
||||
|
|
@ -1523,13 +1441,6 @@ func _on_network_item_use_finished(
|
|||
accepted: bool,
|
||||
message: String,
|
||||
) -> void:
|
||||
if (
|
||||
not accepted
|
||||
and message == PlayerItemEffectsType.FISH_FINDER_DEAD_MESSAGE
|
||||
):
|
||||
status_changed.emit("")
|
||||
local_speech_requested.emit(message)
|
||||
return
|
||||
status_changed.emit(message)
|
||||
if accepted:
|
||||
refresh_active_item_status()
|
||||
|
|
@ -1544,8 +1455,6 @@ func _on_network_cast_accepted(
|
|||
_cast_target = target
|
||||
_bobber_water_position = target
|
||||
state = FishingState.WAITING_FOR_BITE
|
||||
if _active_player != null:
|
||||
_active_player.set_fishing_visual(true)
|
||||
_network_primary_input_held = false
|
||||
_network_input_resend_elapsed = 0.0
|
||||
_presentation.show_withdrawal_position(_bobber_water_position)
|
||||
|
|
@ -1569,24 +1478,10 @@ func _on_network_cast_rejected(message: String) -> void:
|
|||
_cleanup_attempt(visible_message, &"invalid")
|
||||
|
||||
|
||||
func _on_network_bite_pending(_attempt_id: String) -> void:
|
||||
if state != FishingState.WAITING_FOR_BITE:
|
||||
return
|
||||
_stop_reeling_audio()
|
||||
_withdrawal_input_held = false
|
||||
_network_primary_input_held = false
|
||||
_network_input_resend_elapsed = 0.0
|
||||
_set_bite_confirmation_pending(true)
|
||||
status_changed.emit("")
|
||||
_presentation.set_line_mode(FishingPresentationType.LineMode.TAUT)
|
||||
_presentation.show_bite()
|
||||
|
||||
|
||||
func _on_network_bite_started(_attempt_id: String) -> void:
|
||||
if state != FishingState.WAITING_FOR_BITE:
|
||||
return
|
||||
_stop_reeling_audio()
|
||||
_set_bite_confirmation_pending(false)
|
||||
state = FishingState.FIGHTING
|
||||
if _active_player != null:
|
||||
_active_player.set_fighting_visual(true)
|
||||
|
|
@ -1617,10 +1512,7 @@ func _resend_network_input_state(delta: float) -> void:
|
|||
_network_input_resend_elapsed,
|
||||
NETWORK_INPUT_RESEND_INTERVAL_SECONDS,
|
||||
)
|
||||
_network_fishing.submit_local_input(
|
||||
false if _bite_confirmation_pending else _network_primary_input_held,
|
||||
_bite_confirmation_pending and _bite_confirmation_requested,
|
||||
)
|
||||
_network_fishing.submit_local_input(_network_primary_input_held, false)
|
||||
|
||||
|
||||
func _on_network_fishing_snapshot(snapshot: Dictionary) -> void:
|
||||
|
|
@ -1685,7 +1577,6 @@ func _on_network_catch_received(fish_catch: FishCatchType) -> void:
|
|||
_pending_catch = fish_catch
|
||||
if _active_player != null:
|
||||
_active_player.set_fighting_visual(false)
|
||||
_active_player.set_fishing_visual(false)
|
||||
state = FishingState.SHOWING_CATCH
|
||||
_showcase_ready = false
|
||||
_showcase_outcome_completed = false
|
||||
|
|
|
|||
|
|
@ -1,15 +0,0 @@
|
|||
[gd_resource type="Resource" script_class="ItemData" load_steps=2 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://items/item_data.gd" id="1_item"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_item")
|
||||
item_id = &"batteries"
|
||||
display_name = "batteries"
|
||||
description = "replacement batteries for the fish finder."
|
||||
category = 3
|
||||
stackable = true
|
||||
max_stack = 99
|
||||
usable = false
|
||||
equippable = false
|
||||
hotbar_allowed = false
|
||||
|
|
@ -7,11 +7,10 @@
|
|||
script = ExtResource("1")
|
||||
item_id = &"fish_finder"
|
||||
display_name = "fish finder"
|
||||
description = "uses one battery to temporarily shorten bite waits and improve rarity weights."
|
||||
category = 1
|
||||
description = "temporarily shortens bite waits and improves rarity weights."
|
||||
category = 3
|
||||
icon = ExtResource("2")
|
||||
stackable = false
|
||||
max_stack = 1
|
||||
stackable = true
|
||||
max_stack = 99
|
||||
usable = true
|
||||
equippable = true
|
||||
hotbar_allowed = true
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
[gd_resource type="Resource" script_class="ItemCatalog" load_steps=18 format=3]
|
||||
[gd_resource type="Resource" script_class="ItemCatalog" load_steps=16 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://items/item_catalog.gd" id="1_script"]
|
||||
[ext_resource type="Resource" path="res://items/catalog/basic_fishing_rod.tres" id="2_rod"]
|
||||
|
|
@ -15,9 +15,7 @@
|
|||
[ext_resource type="Resource" path="res://items/catalog/whole_anchovy.tres" id="13_anchovy"]
|
||||
[ext_resource type="Resource" path="res://items/catalog/whole_sardine.tres" id="14_sardine"]
|
||||
[ext_resource type="Resource" path="res://items/catalog/luminous_roe.tres" id="15_roe"]
|
||||
[ext_resource type="Resource" path="res://items/catalog/the_standby.tres" id="16_standby"]
|
||||
[ext_resource type="Resource" path="res://items/catalog/batteries.tres" id="17_batteries"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_script")
|
||||
items = [ExtResource("2_rod"), ExtResource("3_coffee"), ExtResource("4_energy"), ExtResource("5_snack"), ExtResource("6_finder"), ExtResource("7_cooler"), ExtResource("8_art_kit"), ExtResource("9_worms"), ExtResource("10_snails"), ExtResource("11_shrimp"), ExtResource("12_squid"), ExtResource("13_anchovy"), ExtResource("14_sardine"), ExtResource("15_roe"), ExtResource("16_standby"), ExtResource("17_batteries")]
|
||||
items = [ExtResource("2_rod"), ExtResource("3_coffee"), ExtResource("4_energy"), ExtResource("5_snack"), ExtResource("6_finder"), ExtResource("7_cooler"), ExtResource("8_art_kit"), ExtResource("9_worms"), ExtResource("10_snails"), ExtResource("11_shrimp"), ExtResource("12_squid"), ExtResource("13_anchovy"), ExtResource("14_sardine"), ExtResource("15_roe")]
|
||||
|
|
|
|||
|
|
@ -1,16 +0,0 @@
|
|||
[gd_resource type="Resource" script_class="ItemData" load_steps=2 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://items/item_data.gd" id="1_item"]
|
||||
|
||||
[resource]
|
||||
script = ExtResource("1_item")
|
||||
item_id = &"the_standby"
|
||||
display_name = "The Standby"
|
||||
description = "holds a bite until you're ready to start the fight."
|
||||
category = 7
|
||||
lure_effects = Array[StringName]([&"deferred_fight"])
|
||||
stackable = false
|
||||
max_stack = 1
|
||||
usable = false
|
||||
equippable = true
|
||||
hotbar_allowed = false
|
||||
|
|
@ -5,8 +5,8 @@
|
|||
[resource]
|
||||
script = ExtResource("1")
|
||||
item_id = &"whole_anchovy"
|
||||
display_name = "sardine"
|
||||
description = "oily schooling bait with high rare catch potential."
|
||||
display_name = "whole anchovy"
|
||||
description = "premium whole bait with high rare catch potential."
|
||||
category = 2
|
||||
bait_tags = Array[StringName]([&"bait_rarity_4"])
|
||||
stackable = true
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@
|
|||
[resource]
|
||||
script = ExtResource("1")
|
||||
item_id = &"whole_sardine"
|
||||
display_name = "minnow"
|
||||
description = "valuable live bait tuned for exceptional catches."
|
||||
display_name = "whole sardine"
|
||||
description = "valuable whole bait tuned for exceptional catches."
|
||||
category = 2
|
||||
bait_tags = Array[StringName]([&"bait_rarity_5"])
|
||||
stackable = true
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ enum Category {
|
|||
@export_multiline var description: String
|
||||
@export var category: Category = Category.UTILITY
|
||||
@export var bait_tags: Array[StringName] = []
|
||||
@export var lure_effects: Array[StringName] = []
|
||||
@export var icon: Texture2D
|
||||
@export var stackable: bool = false
|
||||
@export_range(1, 999, 1) var max_stack: int = 1
|
||||
|
|
@ -41,7 +40,3 @@ func get_category_name() -> String:
|
|||
|
||||
func is_bait() -> bool:
|
||||
return category == Category.BAIT and not bait_tags.is_empty()
|
||||
|
||||
|
||||
func is_lure() -> bool:
|
||||
return category == Category.LURE and equippable
|
||||
|
|
|
|||
|
|
@ -22,10 +22,8 @@ var target: Vector3
|
|||
var bobber_position: Vector3
|
||||
var fish_id: StringName
|
||||
var bait_tags: Array[StringName] = []
|
||||
var lure_effects: Array[StringName] = []
|
||||
var encounter_seed: int = 0
|
||||
var bite_time_remaining: float = 0.0
|
||||
var bite_confirmation_pending: bool = false
|
||||
var withdrawal_progress: float = 0.0
|
||||
var reel_speed: float = 0.0
|
||||
var barrier_damage: int = 1
|
||||
|
|
|
|||
|
|
@ -55,8 +55,6 @@ static func validate_cast_request(data: Variant) -> String:
|
|||
return "Malformed fishing request."
|
||||
if payload.has("bait_id") and typeof(payload["bait_id"]) not in [TYPE_STRING, TYPE_STRING_NAME]:
|
||||
return "Malformed fishing request."
|
||||
if payload.has("lure_id") and typeof(payload["lure_id"]) not in [TYPE_STRING, TYPE_STRING_NAME]:
|
||||
return "Malformed fishing request."
|
||||
var request_id: String = payload["request_id"]
|
||||
var session_id: String = payload["session_id"]
|
||||
var origin: Array = payload["origin"]
|
||||
|
|
@ -91,7 +89,6 @@ static func validate_cast_request(data: Variant) -> String:
|
|||
or discovered.size() > MAX_EVIDENCE_FISH_IDS
|
||||
or str(payload["rod_id"]).is_empty()
|
||||
or str(payload["rod_id"]).length() > 96
|
||||
or str(payload.get("lure_id", "")).length() > 96
|
||||
):
|
||||
return "Fishing request values are outside allowed limits."
|
||||
for value: Variant in rarity:
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ const MIN_CAST_INTERVAL: float = 0.25
|
|||
signal local_cast_accepted(attempt_id: String, target: Vector3)
|
||||
signal local_cast_rejected(message: String)
|
||||
signal local_bite_started(attempt_id: String)
|
||||
signal local_bite_pending(attempt_id: String)
|
||||
signal local_snapshot_received(snapshot: Dictionary)
|
||||
signal local_catch_received(fish_catch: FishCatch)
|
||||
signal local_attempt_ended(outcome: StringName, message: String)
|
||||
|
|
@ -112,7 +111,6 @@ func request_local_cast(
|
|||
"discovered_fish_ids": evidence.get("discovered_fish_ids", []),
|
||||
"capacity_available": bool(evidence.get("capacity_available", false)),
|
||||
"bait_id": str(evidence.get("bait_id", "")),
|
||||
"lure_id": str(evidence.get("lure_id", "")),
|
||||
}
|
||||
if _session.is_host():
|
||||
_handle_cast_request(_session.get_local_peer_id(), data)
|
||||
|
|
@ -178,17 +176,12 @@ func _process(delta: float) -> void:
|
|||
continue
|
||||
match attempt.phase:
|
||||
NetworkFishingAttempt.Phase.WAITING_FOR_BITE:
|
||||
if attempt.bite_confirmation_pending:
|
||||
continue
|
||||
_update_waiting_attempt(attempt, delta)
|
||||
if not _attempts.has(peer_id):
|
||||
continue
|
||||
attempt.bite_time_remaining -= delta
|
||||
if attempt.bite_time_remaining <= 0.0:
|
||||
if &"deferred_fight" in attempt.lure_effects:
|
||||
_set_bite_pending(attempt)
|
||||
else:
|
||||
_start_bite(attempt)
|
||||
_start_bite(attempt)
|
||||
NetworkFishingAttempt.Phase.PENDING_CAPACITY:
|
||||
if now >= attempt.capacity_deadline:
|
||||
_cancel_attempt(peer_id, "Fishing attempt ended.")
|
||||
|
|
@ -303,23 +296,6 @@ func _handle_cast_request(peer_id: int, data: Dictionary) -> void:
|
|||
return
|
||||
var bait_id: StringName = StringName(str(data.get("bait_id", "")))
|
||||
var avatar_bag: PlayerBag = avatar.bag
|
||||
var lure_id: StringName = StringName(str(data.get("lure_id", "")))
|
||||
var lure: ItemDataType = (
|
||||
_item_catalog.get_item_by_id(lure_id)
|
||||
if not lure_id.is_empty() and _item_catalog != null
|
||||
else null
|
||||
)
|
||||
if (
|
||||
not lure_id.is_empty()
|
||||
and (
|
||||
lure == null
|
||||
or not lure.is_lure()
|
||||
or avatar_bag == null
|
||||
or not avatar_bag.owns_item(lure_id)
|
||||
)
|
||||
):
|
||||
_record_and_reject(peer_id, request_id, "Lure is unavailable.")
|
||||
return
|
||||
if not bait_id.is_empty() and (avatar_bag == null or not avatar_bag.remove_item(bait_id, 1)):
|
||||
_record_and_reject(peer_id, request_id, "No bait available.")
|
||||
return
|
||||
|
|
@ -334,10 +310,6 @@ func _handle_cast_request(peer_id: int, data: Dictionary) -> void:
|
|||
attempt.bobber_position = authoritative_target
|
||||
attempt.fish_id = selected_fish.id
|
||||
attempt.bait_tags = _bait_tags_for_request(data)
|
||||
attempt.lure_effects.clear()
|
||||
if lure != null:
|
||||
for effect_id: StringName in lure.lure_effects:
|
||||
attempt.lure_effects.append(effect_id)
|
||||
attempt.reel_speed = float(data["reel_speed"]) * (
|
||||
effects.get_reel_multiplier() if effects != null else 1.0
|
||||
)
|
||||
|
|
@ -465,23 +437,6 @@ func _bait_tags_for_request(data: Dictionary) -> Array[StringName]:
|
|||
return bait.bait_tags.duplicate() if bait != null and bait.is_bait() else []
|
||||
|
||||
|
||||
func _set_bite_pending(attempt: NetworkFishingAttempt) -> void:
|
||||
if (
|
||||
attempt.phase != NetworkFishingAttempt.Phase.WAITING_FOR_BITE
|
||||
or attempt.bite_confirmation_pending
|
||||
):
|
||||
return
|
||||
attempt.bite_confirmation_pending = true
|
||||
attempt.bite_time_remaining = 0.0
|
||||
attempt.input_held = false
|
||||
var data: Dictionary = {
|
||||
"attempt_id": attempt.attempt_id,
|
||||
"owner_peer_id": attempt.owner_peer_id,
|
||||
}
|
||||
_apply_bite_pending(data)
|
||||
receive_bite_pending.rpc(data)
|
||||
|
||||
|
||||
func _start_bite(attempt: NetworkFishingAttempt) -> void:
|
||||
if attempt.phase != NetworkFishingAttempt.Phase.WAITING_FOR_BITE:
|
||||
return
|
||||
|
|
@ -489,7 +444,6 @@ func _start_bite(attempt: NetworkFishingAttempt) -> void:
|
|||
if fish == null or fish.catch_profile == null:
|
||||
_cancel_attempt(attempt.owner_peer_id, "Fishing attempt ended.")
|
||||
return
|
||||
attempt.bite_confirmation_pending = false
|
||||
attempt.phase = NetworkFishingAttempt.Phase.FIGHTING
|
||||
attempt.encounter_seed = _new_seed()
|
||||
var selector := FishSelectorType.new()
|
||||
|
|
@ -542,14 +496,6 @@ func _handle_fishing_input(peer_id: int, data: Dictionary) -> void:
|
|||
return
|
||||
attempt.last_input_sequence = int(data["sequence"])
|
||||
attempt.input_held = bool(data["held"])
|
||||
if (
|
||||
attempt.phase == NetworkFishingAttempt.Phase.WAITING_FOR_BITE
|
||||
and attempt.bite_confirmation_pending
|
||||
):
|
||||
if bool(data["pressed"]):
|
||||
attempt.input_held = false
|
||||
_start_bite(attempt)
|
||||
return
|
||||
if attempt.phase != NetworkFishingAttempt.Phase.FIGHTING:
|
||||
return
|
||||
attempt.controller.set_reel_input(attempt.input_held)
|
||||
|
|
@ -1032,21 +978,6 @@ func _apply_cast_accepted(data: Dictionary) -> void:
|
|||
presentation.show_cast(origin, target)
|
||||
|
||||
|
||||
@rpc("authority", "call_remote", "reliable", 0)
|
||||
func receive_bite_pending(data: Dictionary) -> void:
|
||||
_apply_bite_pending(data)
|
||||
|
||||
|
||||
func _apply_bite_pending(data: Dictionary) -> void:
|
||||
if (
|
||||
typeof(data.get("attempt_id")) != TYPE_STRING
|
||||
or typeof(data.get("owner_peer_id")) != TYPE_INT
|
||||
):
|
||||
return
|
||||
if int(data["owner_peer_id"]) == _session.get_local_peer_id():
|
||||
local_bite_pending.emit(str(data["attempt_id"]))
|
||||
|
||||
|
||||
@rpc("authority", "call_remote", "reliable", 0)
|
||||
func receive_bite_started(data: Dictionary) -> void:
|
||||
_apply_bite_started(data)
|
||||
|
|
|
|||
|
|
@ -50,19 +50,9 @@ func request_use(item_id: StringName) -> String:
|
|||
if not _pending_local.is_empty():
|
||||
local_item_use_finished.emit(false, "An item use is already pending.")
|
||||
return ""
|
||||
var consumed_item_id: StringName = _consumed_item_id(item_id)
|
||||
if item_id == PlayerItemEffects.FISH_FINDER_ID and (
|
||||
_local_bag == null
|
||||
or not _local_bag.owns_item(item_id)
|
||||
or _local_bag.get_quantity(consumed_item_id) < 1
|
||||
):
|
||||
local_item_use_finished.emit(
|
||||
false, PlayerItemEffects.FISH_FINDER_DEAD_MESSAGE
|
||||
)
|
||||
return ""
|
||||
if (
|
||||
_reservations != null
|
||||
and _reservations.get_available_item_quantity(consumed_item_id) < 1
|
||||
and _reservations.get_available_item_quantity(item_id) < 1
|
||||
):
|
||||
local_item_use_finished.emit(false, "Reserved in a letter.")
|
||||
return ""
|
||||
|
|
@ -83,7 +73,7 @@ func request_use(item_id: StringName) -> String:
|
|||
"request_id": request_id,
|
||||
"session_id": _session.get_session_id(),
|
||||
"item_id": str(item_id),
|
||||
"quantity": _local_bag.get_quantity(consumed_item_id),
|
||||
"quantity": _local_bag.get_quantity(item_id),
|
||||
}
|
||||
_pending_local = data.duplicate(true)
|
||||
local_item_use_pending.emit(request_id)
|
||||
|
|
@ -119,28 +109,14 @@ func _handle_use_request(peer_id: int, data: Dictionary) -> void:
|
|||
var item: ItemData = _catalog.get_item_by_id(item_id)
|
||||
var avatar: Player = _spawn_service.get_avatar(peer_id)
|
||||
var duration: float = 0.0
|
||||
var is_fish_finder: bool = (
|
||||
item_id == PlayerItemEffects.FISH_FINDER_ID
|
||||
and item != null
|
||||
and item.category == ItemData.Category.TOOL
|
||||
and item.usable
|
||||
and item.equippable
|
||||
)
|
||||
if error.is_empty() and (
|
||||
item == null
|
||||
or (
|
||||
item.category != ItemData.Category.CONSUMABLE
|
||||
and not is_fish_finder
|
||||
)
|
||||
or item.category != ItemData.Category.CONSUMABLE
|
||||
or not item.usable
|
||||
):
|
||||
error = "That item cannot be used now."
|
||||
if error.is_empty() and int(data["quantity"]) < 1:
|
||||
error = (
|
||||
PlayerItemEffects.FISH_FINDER_DEAD_MESSAGE
|
||||
if is_fish_finder
|
||||
else "You do not have that item."
|
||||
)
|
||||
error = "You do not have that item."
|
||||
if error.is_empty() and (
|
||||
avatar == null
|
||||
or avatar.is_water_recovery_active()
|
||||
|
|
@ -204,10 +180,9 @@ func _apply_result(data: Dictionary) -> void:
|
|||
_acknowledge(data, false, str(data["message"]))
|
||||
return
|
||||
var item_id := StringName(str(data["item_id"]))
|
||||
var consumed_item_id: StringName = _consumed_item_id(item_id)
|
||||
if (
|
||||
_reservations != null
|
||||
and _reservations.get_available_item_quantity(consumed_item_id) < 1
|
||||
and _reservations.get_available_item_quantity(item_id) < 1
|
||||
):
|
||||
_pending_local.clear()
|
||||
local_item_use_finished.emit(false, "Reserved in a letter.")
|
||||
|
|
@ -215,8 +190,8 @@ func _apply_result(data: Dictionary) -> void:
|
|||
return
|
||||
var bag_snapshot := _local_bag.get_all_items()
|
||||
if (
|
||||
_local_bag.get_quantity(consumed_item_id) < 1
|
||||
or not _local_bag.remove_item(consumed_item_id, 1)
|
||||
_local_bag.get_quantity(item_id) < 1
|
||||
or not _local_bag.remove_item(item_id, 1)
|
||||
or not _save_manager.save_if_dirty()
|
||||
):
|
||||
_local_bag.replace_all_items(bag_snapshot)
|
||||
|
|
@ -434,11 +409,3 @@ func _new_id(prefix: String) -> String:
|
|||
return "%s:%s" % [
|
||||
prefix, Crypto.new().generate_random_bytes(16).hex_encode(),
|
||||
]
|
||||
|
||||
|
||||
func _consumed_item_id(item_id: StringName) -> StringName:
|
||||
return (
|
||||
PlayerItemEffects.BATTERIES_ID
|
||||
if item_id == PlayerItemEffects.FISH_FINDER_ID
|
||||
else item_id
|
||||
)
|
||||
|
|
|
|||
|
|
@ -335,29 +335,15 @@ func _build_authoritative_result(
|
|||
var bait_topoff: bool = (
|
||||
FishingShopStockType.is_bait_topoff(product_id)
|
||||
)
|
||||
var permanent_unlock: bool = (
|
||||
FishingShopStockType.is_permanent_unlock(product_id, item)
|
||||
)
|
||||
if (
|
||||
item == null
|
||||
or not item.is_valid()
|
||||
or product_id not in (
|
||||
FishingShopStockType.get_stock_item_ids()
|
||||
)
|
||||
or (
|
||||
item.category != ItemDataType.Category.CONSUMABLE
|
||||
and not bait_topoff
|
||||
and not permanent_unlock
|
||||
)
|
||||
or (not item.stackable and not permanent_unlock)
|
||||
or (
|
||||
not item.usable
|
||||
and not bait_topoff
|
||||
and not permanent_unlock
|
||||
and not FishingShopStockType.is_passive_supply(
|
||||
product_id
|
||||
)
|
||||
)
|
||||
or (item.category != ItemDataType.Category.CONSUMABLE and not bait_topoff)
|
||||
or not item.stackable
|
||||
or (not item.usable and not bait_topoff)
|
||||
or current_state >= item.max_stack
|
||||
or current_state + quantity > item.max_stack
|
||||
):
|
||||
|
|
|
|||
|
|
@ -13,12 +13,12 @@ roughness = 0.8
|
|||
bone_name = "hand.R"
|
||||
|
||||
[node name="FishingRod" type="Node3D" parent="."]
|
||||
rotation_degrees = Vector3(65, 0, 0)
|
||||
rotation_degrees = Vector3(322.6, -31.2, 248.9)
|
||||
|
||||
[node name="RodMesh" type="MeshInstance3D" parent="FishingRod"]
|
||||
position = Vector3(0, 0.5, 0)
|
||||
position = Vector3(0, 0.42, 0)
|
||||
mesh = SubResource("FishingRodMesh")
|
||||
material_override = SubResource("FishingRodMaterial")
|
||||
|
||||
[node name="FishingRodTip" type="Marker3D" parent="FishingRod"]
|
||||
position = Vector3(0, 1.1, 0)
|
||||
position = Vector3(0, 0.95, 0)
|
||||
|
|
|
|||
|
|
@ -41,10 +41,6 @@ const CHARACTER_IDLE_SIT_ANIMATION: StringName = &"idle_sit"
|
|||
const CHARACTER_IDLE_SIT_SHOW_ANIMATION: StringName = &"idle_sit_show"
|
||||
const CHARACTER_WALKING_ANIMATION: StringName = &"walking"
|
||||
const CHARACTER_WALKING_SHOW_ANIMATION: StringName = &"walking_show"
|
||||
const CHARACTER_FISHING_ANIMATION: StringName = &"fishing"
|
||||
const CHARACTER_FISHING_SIT_ANIMATION: StringName = &"fishing_sit"
|
||||
const CHARACTER_FIGHTING_ANIMATION: StringName = &"fighting"
|
||||
const CHARACTER_FIGHTING_SIT_ANIMATION: StringName = &"fighting_sit"
|
||||
const FIGHTING_EYES_ID: String = "alligator_eyes"
|
||||
const BASE_REEL_SPEED: float = 0.16
|
||||
# The target Android handheld exposes its physical right trigger through
|
||||
|
|
@ -57,9 +53,7 @@ var appearance_snapshot: Dictionary = (
|
|||
)
|
||||
var animalese_voice_id: String = "natural"
|
||||
var active_bait_id: StringName = StringName()
|
||||
var active_lure_id: StringName = StringName()
|
||||
signal active_bait_changed(item_id: StringName)
|
||||
signal active_lure_changed(item_id: StringName)
|
||||
|
||||
|
||||
func equip_bait(item: ItemDataType) -> bool:
|
||||
|
|
@ -79,23 +73,6 @@ func unequip_bait() -> void:
|
|||
active_bait_changed.emit(active_bait_id)
|
||||
|
||||
|
||||
func equip_lure(item: ItemDataType) -> bool:
|
||||
if item == null or not item.is_lure() or bag == null:
|
||||
return false
|
||||
if not bag.owns_item(item.item_id):
|
||||
return false
|
||||
active_lure_id = item.item_id
|
||||
active_lure_changed.emit(active_lure_id)
|
||||
return true
|
||||
|
||||
|
||||
func unequip_lure() -> void:
|
||||
if active_lure_id.is_empty():
|
||||
return
|
||||
active_lure_id = StringName()
|
||||
active_lure_changed.emit(active_lure_id)
|
||||
|
||||
|
||||
func apply_appearance_snapshot(snapshot: Dictionary) -> void:
|
||||
if CharacterCustomizationCatalog.validate_snapshot(snapshot):
|
||||
appearance_snapshot = snapshot.duplicate(true)
|
||||
|
|
@ -116,16 +93,6 @@ func set_fighting_visual(active: bool) -> void:
|
|||
return
|
||||
_fighting_visual_active = active
|
||||
_apply_presented_appearance()
|
||||
_character_animation_name = &""
|
||||
_update_character_animation()
|
||||
|
||||
|
||||
func set_fishing_visual(active: bool) -> void:
|
||||
if _fishing_visual_active == active:
|
||||
return
|
||||
_fishing_visual_active = active
|
||||
_character_animation_name = &""
|
||||
_update_character_animation()
|
||||
|
||||
|
||||
func _apply_presented_appearance() -> void:
|
||||
|
|
@ -279,7 +246,6 @@ var _sitting_intent_sequence: int = -1
|
|||
var _held_fish_visible: bool = false
|
||||
var _showcase_animation_active: bool = false
|
||||
var _fighting_visual_active: bool = false
|
||||
var _fishing_visual_active: bool = false
|
||||
var _fishing_rod: Node3D
|
||||
var _fishing_rod_tip: Marker3D
|
||||
var _controller_mapping_manager: ControllerMappingManagerType
|
||||
|
|
@ -302,11 +268,6 @@ func _on_bag_contents_changed() -> void:
|
|||
and bag.get_quantity(active_bait_id) <= 0
|
||||
):
|
||||
unequip_bait()
|
||||
if (
|
||||
not active_lure_id.is_empty()
|
||||
and not bag.owns_item(active_lure_id)
|
||||
):
|
||||
unequip_lure()
|
||||
|
||||
|
||||
func set_controller_mapping_manager(
|
||||
|
|
@ -566,30 +527,6 @@ func _update_character_animation() -> void:
|
|||
&"show",
|
||||
&"show_loop",
|
||||
]
|
||||
elif _fighting_visual_active:
|
||||
if _sitting:
|
||||
requested_animation = [
|
||||
CHARACTER_FIGHTING_SIT_ANIMATION,
|
||||
CHARACTER_IDLE_SIT_ANIMATION,
|
||||
&"idle_sit_loop",
|
||||
]
|
||||
else:
|
||||
requested_animation = [
|
||||
CHARACTER_FIGHTING_ANIMATION,
|
||||
CHARACTER_IDLE_ANIMATION,
|
||||
]
|
||||
elif _fishing_visual_active:
|
||||
if _sitting:
|
||||
requested_animation = [
|
||||
CHARACTER_FISHING_SIT_ANIMATION,
|
||||
CHARACTER_IDLE_SIT_ANIMATION,
|
||||
&"idle_sit_loop",
|
||||
]
|
||||
else:
|
||||
requested_animation = [
|
||||
CHARACTER_FISHING_ANIMATION,
|
||||
CHARACTER_IDLE_ANIMATION,
|
||||
]
|
||||
elif _sitting:
|
||||
if _held_fish_visible:
|
||||
requested_animation = [
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ func _physics_process(delta: float) -> void:
|
|||
_visual.transparency = 1.0 - _opacity
|
||||
|
||||
|
||||
func _place_on_surface(surface_position: Vector3, normal: Vector3) -> void:
|
||||
func _place_on_surface(position: Vector3, normal: Vector3) -> void:
|
||||
var tangent := Vector3.RIGHT - normal * Vector3.RIGHT.dot(normal)
|
||||
if tangent.length_squared() < 0.001:
|
||||
tangent = Vector3.FORWARD - normal * Vector3.FORWARD.dot(normal)
|
||||
|
|
@ -62,5 +62,5 @@ func _place_on_surface(surface_position: Vector3, normal: Vector3) -> void:
|
|||
var bitangent := tangent.cross(normal).normalized()
|
||||
_placement.global_transform = Transform3D(
|
||||
Basis(tangent, normal, bitangent),
|
||||
surface_position + normal * surface_offset,
|
||||
position + normal * surface_offset,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -10,8 +10,6 @@ const COFFEE_ID: StringName = &"coffee"
|
|||
const ENERGY_DRINK_ID: StringName = &"energy_drink"
|
||||
const SNACK_ID: StringName = &"snack"
|
||||
const FISH_FINDER_ID: StringName = &"fish_finder"
|
||||
const BATTERIES_ID: StringName = &"batteries"
|
||||
const FISH_FINDER_DEAD_MESSAGE: String = "hmm... batteries are dead..."
|
||||
const COFFEE_DURATION: float = 90.0
|
||||
const ENERGY_DRINK_DURATION: float = 90.0
|
||||
const SNACK_DURATION: float = 60.0
|
||||
|
|
@ -47,35 +45,16 @@ func use_consumable(
|
|||
item: ItemDataType,
|
||||
bag: PlayerBagType,
|
||||
) -> bool:
|
||||
return use_item(item, bag)
|
||||
|
||||
|
||||
func use_item(
|
||||
item: ItemDataType,
|
||||
bag: PlayerBagType,
|
||||
) -> bool:
|
||||
var is_fish_finder: bool = (
|
||||
item != null
|
||||
and item.item_id == FISH_FINDER_ID
|
||||
and item.category == ItemDataType.Category.TOOL
|
||||
and item.equippable
|
||||
)
|
||||
if (
|
||||
item == null
|
||||
or bag == null
|
||||
or (
|
||||
item.category != ItemDataType.Category.CONSUMABLE
|
||||
and not is_fish_finder
|
||||
)
|
||||
or item.category != ItemDataType.Category.CONSUMABLE
|
||||
or not item.usable
|
||||
or not _remaining.has(item.item_id)
|
||||
or not bag.owns_item(item.item_id)
|
||||
):
|
||||
return false
|
||||
var consumed_item_id: StringName = (
|
||||
BATTERIES_ID if is_fish_finder else item.item_id
|
||||
)
|
||||
if not bag.remove_item(consumed_item_id, 1):
|
||||
if not bag.remove_item(item.item_id, 1):
|
||||
return false
|
||||
_remaining[item.item_id] = _get_duration(item.item_id)
|
||||
effects_changed.emit()
|
||||
|
|
|
|||
|
|
@ -34,10 +34,6 @@ const CLOCK_SIZE := Vector2(116.0, 34.0)
|
|||
const CLOCK_EDGE_MARGIN: float = 10.0
|
||||
const WEATHER_ICON_SIZE := Vector2(34.0, 34.0)
|
||||
const WEATHER_ICON_GAP: float = 6.0
|
||||
const FISH_FINDER_EFFECT_ICON_SIZE := Vector2(18.0, 18.0)
|
||||
const FISH_FINDER_EFFECT_ICON: Texture2D = preload(
|
||||
"res://items/icons/consumables/64_consumable_fishfinder.png"
|
||||
)
|
||||
const CHAT_SHOW_ICON: Texture2D = preload(
|
||||
"res://ui/icons/pictograms/arrow_light_right_more.png"
|
||||
)
|
||||
|
|
@ -90,7 +86,6 @@ var _animalese_voice: AnimaleseVoiceType
|
|||
var _clock_panel: PanelContainer
|
||||
var _clock_label: Label
|
||||
var _weather_icon: WeatherIconType
|
||||
var _fish_finder_effect_icon: TextureRect
|
||||
var _speech: Dictionary[int, Dictionary] = {}
|
||||
var _draft_save_timer: Timer
|
||||
var _opacity_tween: Tween
|
||||
|
|
@ -115,7 +110,6 @@ var _dock_right: bool = false
|
|||
var _mobile_mode: bool = false
|
||||
var _world_time: WorldTimeServiceType
|
||||
var _world_weather: WorldWeatherServiceType
|
||||
var _item_effects: PlayerItemEffects
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
|
|
@ -135,7 +129,6 @@ func setup(
|
|||
settings: PlayerSettingsManager,
|
||||
world_time: WorldTimeServiceType,
|
||||
world_weather: WorldWeatherServiceType,
|
||||
item_effects: PlayerItemEffects,
|
||||
) -> void:
|
||||
_service = service
|
||||
_session = session
|
||||
|
|
@ -145,14 +138,6 @@ func setup(
|
|||
_settings = settings
|
||||
_world_time = world_time
|
||||
_world_weather = world_weather
|
||||
_item_effects = item_effects
|
||||
if (
|
||||
_fishing_spot != null
|
||||
and not _fishing_spot.local_speech_requested.is_connected(
|
||||
show_local_speech
|
||||
)
|
||||
):
|
||||
_fishing_spot.local_speech_requested.connect(show_local_speech)
|
||||
if (
|
||||
_world_time != null
|
||||
and not _world_time.time_changed.is_connected(
|
||||
|
|
@ -376,15 +361,6 @@ func _build_ui() -> void:
|
|||
"font_color", UtilityPageStyle.OCEAN_TEXT_PRIMARY
|
||||
)
|
||||
_clock_panel.add_child(_clock_label)
|
||||
_fish_finder_effect_icon = TextureRect.new()
|
||||
_fish_finder_effect_icon.name = "FishFinderEffectIcon"
|
||||
_fish_finder_effect_icon.texture = FISH_FINDER_EFFECT_ICON
|
||||
_fish_finder_effect_icon.size = FISH_FINDER_EFFECT_ICON_SIZE
|
||||
_fish_finder_effect_icon.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
|
||||
_fish_finder_effect_icon.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
|
||||
_fish_finder_effect_icon.texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST
|
||||
_fish_finder_effect_icon.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
add_child(_fish_finder_effect_icon)
|
||||
_weather_icon = WeatherIconType.new()
|
||||
_weather_icon.name = "WorldWeatherIcon"
|
||||
_weather_icon.size = WEATHER_ICON_SIZE
|
||||
|
|
@ -824,24 +800,6 @@ func _on_message(message: Dictionary) -> void:
|
|||
if int(message["kind"]) != NetworkChatProtocol.Kind.PLAYER:
|
||||
return
|
||||
var peer_id: int = message["sender_peer_id"]
|
||||
_show_speech_bubble(
|
||||
peer_id,
|
||||
str(message["body"]),
|
||||
str(message.get("sender_fingerprint", "")),
|
||||
)
|
||||
|
||||
|
||||
func show_local_speech(body: String) -> void:
|
||||
if body.strip_edges().is_empty() or _session == null:
|
||||
return
|
||||
_show_speech_bubble(_session.get_local_peer_id(), body, "")
|
||||
|
||||
|
||||
func _show_speech_bubble(
|
||||
peer_id: int,
|
||||
body: String,
|
||||
fingerprint: String,
|
||||
) -> void:
|
||||
_on_peer_removed(peer_id)
|
||||
var bubble := PanelContainer.new()
|
||||
bubble.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
|
|
@ -850,7 +808,7 @@ func _show_speech_bubble(
|
|||
var pointer := _create_speech_pointer()
|
||||
bubble.add_child(pointer)
|
||||
var label := Label.new()
|
||||
label.text = body
|
||||
label.text = str(message["body"])
|
||||
label.custom_minimum_size = Vector2(
|
||||
SPEECH_BUBBLE_WIDTH - 20.0,
|
||||
0.0,
|
||||
|
|
@ -886,7 +844,7 @@ func _show_speech_bubble(
|
|||
+ reveal_seconds
|
||||
+ SPEECH_SECONDS
|
||||
),
|
||||
"fingerprint": fingerprint,
|
||||
"fingerprint": str(message.get("sender_fingerprint", "")),
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -933,7 +891,6 @@ func _refresh_visibility() -> void:
|
|||
_panel.hide()
|
||||
_clock_panel.hide()
|
||||
_weather_icon.hide()
|
||||
_fish_finder_effect_icon.hide()
|
||||
_collapse_button.hide()
|
||||
_height_button.hide()
|
||||
_unread_indicator.hide()
|
||||
|
|
@ -941,10 +898,6 @@ func _refresh_visibility() -> void:
|
|||
return
|
||||
_clock_panel.show()
|
||||
_weather_icon.show()
|
||||
_fish_finder_effect_icon.visible = (
|
||||
_item_effects != null
|
||||
and _item_effects.is_active(PlayerItemEffects.FISH_FINDER_ID)
|
||||
)
|
||||
_collapse_button.show()
|
||||
var collapsed := _presentation_state == PresentationState.COLLAPSED
|
||||
_panel.show()
|
||||
|
|
@ -1279,11 +1232,6 @@ func _layout_presentation(animate: bool) -> void:
|
|||
clock_x,
|
||||
CLOCK_EDGE_MARGIN,
|
||||
)
|
||||
var fish_finder_effect_position := Vector2(
|
||||
clock_position.x
|
||||
+ (CLOCK_SIZE.x - FISH_FINDER_EFFECT_ICON_SIZE.x) * 0.5,
|
||||
clock_position.y + CLOCK_SIZE.y + 2.0,
|
||||
)
|
||||
var weather_icon_x: float = (
|
||||
clock_position.x - WEATHER_ICON_GAP - WEATHER_ICON_SIZE.x
|
||||
if _dock_right
|
||||
|
|
@ -1307,8 +1255,6 @@ func _layout_presentation(animate: bool) -> void:
|
|||
_panel.size = target_size
|
||||
_clock_panel.position = clock_position
|
||||
_clock_panel.size = CLOCK_SIZE
|
||||
_fish_finder_effect_icon.position = fish_finder_effect_position
|
||||
_fish_finder_effect_icon.size = FISH_FINDER_EFFECT_ICON_SIZE
|
||||
_weather_icon.position = weather_icon_position
|
||||
_weather_icon.size = WEATHER_ICON_SIZE
|
||||
_collapse_button.position = collapse_position
|
||||
|
|
@ -1329,12 +1275,6 @@ func _layout_presentation(animate: bool) -> void:
|
|||
clock_position,
|
||||
UIMotion.CHAT_RESIZE_DURATION,
|
||||
).set_trans(Tween.TRANS_QUAD).set_ease(Tween.EASE_OUT)
|
||||
_height_tween.tween_property(
|
||||
_fish_finder_effect_icon,
|
||||
"position",
|
||||
fish_finder_effect_position,
|
||||
UIMotion.CHAT_RESIZE_DURATION,
|
||||
).set_trans(Tween.TRANS_QUAD).set_ease(Tween.EASE_OUT)
|
||||
_height_tween.tween_property(
|
||||
_weather_icon,
|
||||
"position",
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ const ShopInteractionType = preload(
|
|||
"res://world/fishing_shop_interaction.gd"
|
||||
)
|
||||
const UtilityPageStyleType = preload("res://ui/utility_page_style.gd")
|
||||
const OrganizerTabType = preload("res://ui/components/organizer_tab.gd")
|
||||
|
||||
signal menu_visibility_changed(is_open: bool)
|
||||
signal sell_fish_requested
|
||||
|
|
@ -40,22 +39,6 @@ enum CloseReason {
|
|||
TEARDOWN,
|
||||
}
|
||||
|
||||
enum ShopSection {
|
||||
UPGRADES,
|
||||
BAIT,
|
||||
SNACKS,
|
||||
EQUIPMENT,
|
||||
ART_SUPPLIES,
|
||||
}
|
||||
|
||||
const SHOP_SECTION_LABELS: Array[String] = [
|
||||
"Upgrades",
|
||||
"Bait",
|
||||
"Snacks",
|
||||
"Equipment",
|
||||
"Art Supplies",
|
||||
]
|
||||
|
||||
@onready var _wallet_label: Label = %WalletLabel
|
||||
@onready var _shop_panel: PanelContainer = %ShopPanel
|
||||
@onready var _shop_cooler_page: Control = %ShopCoolerPage
|
||||
|
|
@ -64,10 +47,6 @@ const SHOP_SECTION_LABELS: Array[String] = [
|
|||
@onready var _buy_mode_button: Button = %BuyModeButton
|
||||
@onready var _sell_mode_button: Button = %SellModeButton
|
||||
@onready var _feedback: Label = %Feedback
|
||||
@onready var _shop_tab_bar: HBoxContainer = %ShopTabBar
|
||||
@onready var _upgrades_content: VBoxContainer = %Upgrades
|
||||
@onready var _supplies_content: VBoxContainer = %Supplies
|
||||
@onready var _stock_title: Label = %StockTitle
|
||||
@onready var _reel_level: Label = %ReelLevel
|
||||
@onready var _reel_effect: Label = %ReelEffect
|
||||
@onready var _reel_cost: Label = %ReelCost
|
||||
|
|
@ -102,14 +81,11 @@ var _transaction_in_progress: bool = false
|
|||
var _closing: bool = false
|
||||
var _cooler_page_active: bool = false
|
||||
var _cooler_modal_open: bool = false
|
||||
var _shop_section: ShopSection = ShopSection.UPGRADES
|
||||
var _shop_tabs: Array[OrganizerTab] = []
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
UtilityPageStyleType.apply_page(self)
|
||||
_apply_shop_styles()
|
||||
_build_shop_tabs()
|
||||
%CloseButton.pressed.connect(close_shop)
|
||||
_buy_mode_button.pressed.connect(_focus_buy_page)
|
||||
_sell_mode_button.pressed.connect(_request_shop_cooler)
|
||||
|
|
@ -131,39 +107,12 @@ func _request_shop_cooler() -> void:
|
|||
|
||||
func _focus_buy_page() -> void:
|
||||
_feedback.text = ""
|
||||
if _shop_section == ShopSection.UPGRADES:
|
||||
_reel_purchase.grab_focus()
|
||||
return
|
||||
for child: Node in _supplies_list.get_children():
|
||||
var stock_button := child as Button
|
||||
if stock_button != null and not stock_button.disabled:
|
||||
stock_button.grab_focus()
|
||||
return
|
||||
_buy_mode_button.grab_focus()
|
||||
|
||||
|
||||
func _build_shop_tabs() -> void:
|
||||
for section_index: int in range(ShopSection.size()):
|
||||
var tab: OrganizerTab = OrganizerTabType.new()
|
||||
tab.text = SHOP_SECTION_LABELS[section_index]
|
||||
tab.palette_index = section_index
|
||||
tab.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
tab.pressed.connect(_select_shop_section.bind(section_index, true))
|
||||
_shop_tab_bar.add_child(tab)
|
||||
_shop_tabs.append(tab)
|
||||
_select_shop_section(ShopSection.UPGRADES, false)
|
||||
|
||||
|
||||
func _select_shop_section(section_index: int, focus_content: bool) -> void:
|
||||
_shop_section = section_index as ShopSection
|
||||
var showing_upgrades: bool = _shop_section == ShopSection.UPGRADES
|
||||
_upgrades_content.visible = showing_upgrades
|
||||
_supplies_content.visible = not showing_upgrades
|
||||
for tab_index: int in range(_shop_tabs.size()):
|
||||
_shop_tabs[tab_index].set_selected(tab_index == section_index, true)
|
||||
_refresh_supplies()
|
||||
if focus_content and visible:
|
||||
_focus_buy_page()
|
||||
_reel_purchase.grab_focus()
|
||||
|
||||
|
||||
func _apply_shop_styles() -> void:
|
||||
|
|
@ -287,7 +236,6 @@ func open_shop() -> bool:
|
|||
_feedback.text = ""
|
||||
deactivate_shop_cooler_page()
|
||||
show()
|
||||
_select_shop_section(ShopSection.UPGRADES, false)
|
||||
_refresh_all()
|
||||
_buy_mode_button.grab_focus()
|
||||
menu_visibility_changed.emit(true)
|
||||
|
|
@ -465,12 +413,10 @@ func _refresh_supplies() -> void:
|
|||
for child: Node in _supplies_list.get_children():
|
||||
_supplies_list.remove_child(child)
|
||||
child.queue_free()
|
||||
if _shop_section == ShopSection.UPGRADES:
|
||||
return
|
||||
_stock_title.text = SHOP_SECTION_LABELS[int(_shop_section)]
|
||||
_add_stock_section("supplies")
|
||||
for item_id: StringName in FishingShopStockType.get_stock_item_ids():
|
||||
var item: ItemDataType = _item_catalog.get_item_by_id(item_id)
|
||||
if item == null or not _item_belongs_in_current_section(item):
|
||||
if item == null:
|
||||
continue
|
||||
var button := Button.new()
|
||||
button.custom_minimum_size = Vector2(195, 54)
|
||||
|
|
@ -546,32 +492,17 @@ func _refresh_supplies() -> void:
|
|||
UtilityPageStyleType.apply_ocean_button(button)
|
||||
button.pressed.connect(_purchase_supply.bind(item_id))
|
||||
_supplies_list.add_child(button)
|
||||
if _shop_section == ShopSection.ART_SUPPLIES:
|
||||
_add_stock_section("art kit")
|
||||
_add_art_kit_button()
|
||||
_add_stock_section("markers")
|
||||
for product_id: StringName in ArtShopStockType.MARKER_PRODUCTS:
|
||||
_add_art_upgrade_button(product_id)
|
||||
_add_stock_section("brushes")
|
||||
for product_id: StringName in ArtShopStockType.BRUSH_PRODUCTS:
|
||||
_add_art_upgrade_button(product_id)
|
||||
_add_stock_section("grids")
|
||||
for product_id: StringName in ArtShopStockType.GRID_PRODUCTS:
|
||||
_add_art_upgrade_button(product_id)
|
||||
|
||||
|
||||
func _item_belongs_in_current_section(item: ItemDataType) -> bool:
|
||||
match _shop_section:
|
||||
ShopSection.BAIT:
|
||||
return item.is_bait()
|
||||
ShopSection.SNACKS:
|
||||
return item.category == ItemDataType.Category.CONSUMABLE
|
||||
ShopSection.EQUIPMENT:
|
||||
return item.category in [
|
||||
ItemDataType.Category.TOOL,
|
||||
ItemDataType.Category.LURE,
|
||||
]
|
||||
return false
|
||||
_add_stock_section("art kit")
|
||||
_add_art_kit_button()
|
||||
_add_stock_section("markers")
|
||||
for product_id: StringName in ArtShopStockType.MARKER_PRODUCTS:
|
||||
_add_art_upgrade_button(product_id)
|
||||
_add_stock_section("brushes")
|
||||
for product_id: StringName in ArtShopStockType.BRUSH_PRODUCTS:
|
||||
_add_art_upgrade_button(product_id)
|
||||
_add_stock_section("grids")
|
||||
for product_id: StringName in ArtShopStockType.GRID_PRODUCTS:
|
||||
_add_art_upgrade_button(product_id)
|
||||
|
||||
|
||||
func _add_stock_section(title: String) -> void:
|
||||
|
|
|
|||
|
|
@ -143,19 +143,12 @@ text = ""
|
|||
horizontal_alignment = 1
|
||||
theme_override_colors/font_color = Color(1, 0.82, 0.4, 1)
|
||||
|
||||
[node name="ShopTabBar" type="HBoxContainer" parent="ShopPanel/Margin/Layout"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
alignment = 1
|
||||
theme_override_constants/separation = 6
|
||||
|
||||
[node name="Body" type="HBoxContainer" parent="ShopPanel/Margin/Layout"]
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
theme_override_constants/separation = 0
|
||||
theme_override_constants/separation = 12
|
||||
|
||||
[node name="Upgrades" type="VBoxContainer" parent="ShopPanel/Margin/Layout/Body"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(270, 0)
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
|
@ -167,14 +160,12 @@ text = "fishing upgrades"
|
|||
theme_override_font_sizes/font_size = 23
|
||||
|
||||
[node name="Supplies" type="VBoxContainer" parent="ShopPanel/Margin/Layout/Body"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(210, 0)
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
theme_override_constants/separation = 6
|
||||
|
||||
[node name="StockTitle" type="Label" parent="ShopPanel/Margin/Layout/Body/Supplies"]
|
||||
unique_name_in_owner = true
|
||||
[node name="Title" type="Label" parent="ShopPanel/Margin/Layout/Body/Supplies"]
|
||||
layout_mode = 2
|
||||
text = "shop stock"
|
||||
theme_override_font_sizes/font_size = 23
|
||||
|
|
|
|||
|
|
@ -91,7 +91,6 @@ const FISHING_PANEL_SHOWCASE_TOP_OFFSET: float = -174.0
|
|||
const FISHING_PANEL_SHOWCASE_BOTTOM_OFFSET: float = -104.0
|
||||
|
||||
@onready var _status_label: Label = %StatusLabel
|
||||
@onready var _bite_prompt_button: Button = %BitePromptButton
|
||||
@onready var _gameplay_transient_hud: Control = %GameplayTransientHUD
|
||||
@onready var _active_bait_button: Button = %ActiveBaitButton
|
||||
@onready var _active_bait_quantity_badge: Panel = %ActiveBaitQuantityBadge
|
||||
|
|
@ -191,7 +190,6 @@ var _settings_manager: PlayerSettingsManagerType
|
|||
|
||||
|
||||
func _ready() -> void:
|
||||
_bite_prompt_button.pressed.connect(_on_bite_prompt_pressed)
|
||||
_apply_active_bait_indicator_style()
|
||||
_refresh_active_bait_indicator()
|
||||
# Reward feedback must remain above full-screen canonical menus. Keeping the
|
||||
|
|
@ -309,7 +307,7 @@ func setup(
|
|||
_experience.experience_awarded.connect(_on_experience_awarded)
|
||||
_chat_ui.setup(
|
||||
network_chat_service, network_session, spawn_service, player,
|
||||
fishing_spot, settings_manager, world_time, world_weather, item_effects
|
||||
fishing_spot, settings_manager, world_time, world_weather
|
||||
)
|
||||
_title_settings_panel.setup_network_profile(
|
||||
network_profile, network_session
|
||||
|
|
@ -318,7 +316,6 @@ func setup(
|
|||
network_profile, network_session
|
||||
)
|
||||
fishing_spot.status_changed.connect(_on_fishing_status_changed)
|
||||
fishing_spot.bite_prompt_changed.connect(_on_bite_prompt_changed)
|
||||
fishing_spot.catch_display_changed.connect(_on_catch_display_changed)
|
||||
fishing_spot.showcase_changed.connect(_on_showcase_changed)
|
||||
fishing_spot.art_ui_toggle_requested.connect(_toggle_surface_drawing)
|
||||
|
|
@ -1593,7 +1590,6 @@ func _refresh_fishing_panel_visibility() -> void:
|
|||
var has_content: bool = (
|
||||
not _status_label.text.strip_edges().is_empty()
|
||||
or not _showcase_details.text.strip_edges().is_empty()
|
||||
or _bite_prompt_button.visible
|
||||
)
|
||||
_fishing_panel.visible = (
|
||||
_gameplay_ui_enabled
|
||||
|
|
@ -1601,16 +1597,6 @@ func _refresh_fishing_panel_visibility() -> void:
|
|||
)
|
||||
|
||||
|
||||
func _on_bite_prompt_changed(is_visible: bool) -> void:
|
||||
_bite_prompt_button.visible = is_visible
|
||||
_refresh_fishing_panel_visibility()
|
||||
|
||||
|
||||
func _on_bite_prompt_pressed() -> void:
|
||||
if _fishing_spot != null:
|
||||
_fishing_spot.confirm_pending_bite()
|
||||
|
||||
|
||||
func _on_catch_display_changed(
|
||||
progress: float,
|
||||
chase_progress: float,
|
||||
|
|
|
|||
|
|
@ -279,16 +279,6 @@ text = ""
|
|||
horizontal_alignment = 1
|
||||
theme_override_font_sizes/font_size = 16
|
||||
|
||||
[node name="BitePromptButton" type="Button" parent="UIRoot/CanonicalStage/GameplayTransientHUD/FishingPanel/MarginContainer/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
custom_minimum_size = Vector2(0, 42)
|
||||
layout_mode = 2
|
||||
focus_mode = 0
|
||||
mouse_default_cursor_shape = 2
|
||||
text = "you got a bite!"
|
||||
theme_override_font_sizes/font_size = 22
|
||||
|
||||
[node name="ShowcaseDetails" type="Label" parent="UIRoot/CanonicalStage/GameplayTransientHUD/FishingPanel/MarginContainer/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
|
|
|
|||
|
|
@ -189,7 +189,6 @@ const SALE_CONFIRMATION_SIZE := Vector2(520.0, 190.0)
|
|||
@onready var _cooler_combined_offer_value: Label = %CoolerCombinedOfferValue
|
||||
@onready var _favorite_bubble: NotepadInkActionType = %FavoriteBubble
|
||||
@onready var _sell_bubble: NotepadInkActionType = %SellBubble
|
||||
@onready var _sell_all_bubble: NotepadInkActionType = %SellAllBubble
|
||||
@onready var _bag_page: Control = %BagPage
|
||||
@onready var _tackle_box_page: Control = %TackleBoxPage
|
||||
@onready var _inventory_sub_tabs: HBoxContainer = %InventorySubTabs
|
||||
|
|
@ -393,7 +392,7 @@ func _ready() -> void:
|
|||
)
|
||||
_bait_filter.pressed.connect(_set_tackle_view.bind(TackleView.BAIT))
|
||||
_lures_filter.pressed.connect(_set_tackle_view.bind(TackleView.LURES))
|
||||
_tackle_equip_button.pressed.connect(_toggle_active_tackle)
|
||||
_tackle_equip_button.pressed.connect(_toggle_active_bait)
|
||||
_logbook_tab.pressed.connect(
|
||||
_show_section.bind(Section.LOGBOOK)
|
||||
)
|
||||
|
|
@ -410,7 +409,6 @@ func _ready() -> void:
|
|||
_sell_button.pressed.connect(_on_sell_pressed)
|
||||
_favorite_bubble.pressed.connect(_on_favorite_pressed)
|
||||
_sell_bubble.pressed.connect(_on_sell_pressed)
|
||||
_sell_all_bubble.pressed.connect(_on_sell_all_pressed)
|
||||
_confirm_sale_button.pressed.connect(_on_confirm_sale_pressed)
|
||||
_cancel_sale_button.pressed.connect(_close_sale_confirmation)
|
||||
_configure_sale_confirmation_focus()
|
||||
|
|
@ -595,8 +593,6 @@ func setup(
|
|||
_bag.contents_changed.connect(_on_bag_changed)
|
||||
if not _player.active_bait_changed.is_connected(_on_active_bait_changed):
|
||||
_player.active_bait_changed.connect(_on_active_bait_changed)
|
||||
if not _player.active_lure_changed.is_connected(_on_active_lure_changed):
|
||||
_player.active_lure_changed.connect(_on_active_lure_changed)
|
||||
if not _hotbar.slots_changed.is_connected(_on_hotbar_changed):
|
||||
_hotbar.slots_changed.connect(_on_hotbar_changed)
|
||||
if not _cooler_capacity.capacity_changed.is_connected(
|
||||
|
|
@ -758,8 +754,6 @@ func _try_enter_notepad_controller_ownership() -> bool:
|
|||
actions.append(_favorite_bubble)
|
||||
if not _sell_bubble.disabled:
|
||||
actions.append(_sell_bubble)
|
||||
if not _sell_all_bubble.disabled:
|
||||
actions.append(_sell_all_bubble)
|
||||
elif _current_section == Section.TACKLE_BOX:
|
||||
if not focus_owner.has_meta(&"controller_tackle_item_id"):
|
||||
return false
|
||||
|
|
@ -1949,30 +1943,21 @@ func _refresh_tackle_box() -> void:
|
|||
var item: ItemDataType = _item_catalog.get_item_by_id(owned.item_id)
|
||||
var row := Button.new()
|
||||
row.icon = item.icon
|
||||
row.tooltip_text = (
|
||||
"%s ×%d" % [item.display_name, owned.quantity]
|
||||
if item.is_bait()
|
||||
else item.display_name
|
||||
)
|
||||
var compact_tackle_item: bool = item.is_bait() or item.is_lure()
|
||||
if compact_tackle_item:
|
||||
row.tooltip_text = "%s ×%d" % [item.display_name, owned.quantity]
|
||||
if item.is_bait() and item.icon != null:
|
||||
row.custom_minimum_size = Vector2(72, 72)
|
||||
row.size_flags_horizontal = Control.SIZE_SHRINK_BEGIN
|
||||
row.expand_icon = item.icon != null
|
||||
row.expand_icon = true
|
||||
row.alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
row.text = "" if item.icon != null else item.display_name
|
||||
if item.icon == null:
|
||||
row.add_theme_font_size_override("font_size", 12)
|
||||
else:
|
||||
row.text = "%s ×%d" % [item.display_name, owned.quantity]
|
||||
row.alignment = HORIZONTAL_ALIGNMENT_LEFT
|
||||
row.toggle_mode = true
|
||||
row.set_meta(&"controller_tackle_item_id", owned.item_id)
|
||||
row.button_pressed = owned.item_id == _selected_tackle_item_id
|
||||
if compact_tackle_item:
|
||||
if item.is_bait() and item.icon != null:
|
||||
_apply_tackle_bait_button_style(row)
|
||||
if item.is_bait():
|
||||
_add_tackle_quantity_badge(row, owned.quantity)
|
||||
_add_tackle_quantity_badge(row, owned.quantity)
|
||||
else:
|
||||
UtilityPageStyle.apply_ocean_button(row)
|
||||
row.pressed.connect(_select_tackle_item.bind(owned.item_id))
|
||||
|
|
@ -2068,7 +2053,7 @@ func _update_tackle_detail() -> void:
|
|||
else "Select a lure for details."
|
||||
)
|
||||
return
|
||||
_tackle_equip_button.visible = item.is_bait() or item.is_lure()
|
||||
_tackle_equip_button.visible = item.is_bait()
|
||||
var quantity: int = _bag.get_quantity(item.item_id) if _bag != null else 0
|
||||
var assigned_slot: int = -1
|
||||
if _hotbar != null:
|
||||
|
|
@ -2076,22 +2061,19 @@ func _update_tackle_detail() -> void:
|
|||
if _hotbar.get_item_id(slot_index) == item.item_id:
|
||||
assigned_slot = slot_index
|
||||
break
|
||||
var detail_lines: Array[String] = [item.display_name, ""]
|
||||
if item.is_bait():
|
||||
detail_lines.append("quantity: %d" % quantity)
|
||||
var detail_lines: Array[String] = [
|
||||
item.display_name,
|
||||
"",
|
||||
"quantity: %d" % quantity,
|
||||
]
|
||||
if assigned_slot >= 0:
|
||||
detail_lines.append("hotbar slot %d" % (assigned_slot + 1))
|
||||
detail_lines.append("")
|
||||
detail_lines.append(item.description)
|
||||
_tackle_detail_text.text = "\n".join(detail_lines)
|
||||
if item.is_bait() or item.is_lure():
|
||||
if item.is_bait():
|
||||
var is_equipped: bool = (
|
||||
_player != null
|
||||
and (
|
||||
_player.active_bait_id == item.item_id
|
||||
if item.is_bait()
|
||||
else _player.active_lure_id == item.item_id
|
||||
)
|
||||
_player != null and _player.active_bait_id == item.item_id
|
||||
)
|
||||
_tackle_equip_button.text = (
|
||||
"dequip %s" % item.display_name
|
||||
|
|
@ -2103,24 +2085,16 @@ func _update_tackle_detail() -> void:
|
|||
_tackle_equip_button.refresh_ink_state()
|
||||
|
||||
|
||||
func _toggle_active_tackle() -> void:
|
||||
func _toggle_active_bait() -> void:
|
||||
if _player == null or _item_catalog == null:
|
||||
return
|
||||
var item: ItemDataType = _item_catalog.get_item_by_id(_selected_tackle_item_id)
|
||||
if item == null:
|
||||
if item == null or not item.is_bait():
|
||||
return
|
||||
if item.is_bait():
|
||||
if _player.active_bait_id == item.item_id:
|
||||
_player.unequip_bait()
|
||||
else:
|
||||
_player.equip_bait(item)
|
||||
elif item.is_lure():
|
||||
if _player.active_lure_id == item.item_id:
|
||||
_player.unequip_lure()
|
||||
else:
|
||||
_player.equip_lure(item)
|
||||
if _player.active_bait_id == item.item_id:
|
||||
_player.unequip_bait()
|
||||
else:
|
||||
return
|
||||
_player.equip_bait(item)
|
||||
_update_tackle_detail()
|
||||
|
||||
|
||||
|
|
@ -2128,10 +2102,6 @@ func _on_active_bait_changed(_item_id: StringName) -> void:
|
|||
_update_tackle_detail()
|
||||
|
||||
|
||||
func _on_active_lure_changed(_item_id: StringName) -> void:
|
||||
_update_tackle_detail()
|
||||
|
||||
|
||||
func _apply_cooler_control_styles() -> void:
|
||||
var profile: BubbleMenuProfile = _inventory_tab.profile
|
||||
if profile == null:
|
||||
|
|
@ -2456,9 +2426,6 @@ func _update_shell_layout() -> void:
|
|||
_sell_bubble.custom_minimum_size = (
|
||||
Vector2(74.0, 42.0) if compact else Vector2(118.0, 50.0)
|
||||
)
|
||||
_sell_all_bubble.custom_minimum_size = (
|
||||
Vector2(96.0, 38.0) if compact else Vector2(122.0, 44.0)
|
||||
)
|
||||
_favorite_bubble.position = (
|
||||
Vector2(144.0, 148.0) if compact else Vector2(26.0, 378.0)
|
||||
)
|
||||
|
|
@ -2471,21 +2438,12 @@ func _update_shell_layout() -> void:
|
|||
_sell_bubble.size = (
|
||||
Vector2(74.0, 42.0) if compact else Vector2(118.0, 50.0)
|
||||
)
|
||||
_sell_all_bubble.position = (
|
||||
Vector2(102.0, 190.0) if compact else Vector2(78.0, 426.0)
|
||||
)
|
||||
_sell_all_bubble.size = (
|
||||
Vector2(96.0, 38.0) if compact else Vector2(122.0, 44.0)
|
||||
)
|
||||
_favorite_bubble.add_theme_font_size_override(
|
||||
"font_size", 11 if compact else 17,
|
||||
)
|
||||
_sell_bubble.add_theme_font_size_override(
|
||||
"font_size", 11 if compact else 17,
|
||||
)
|
||||
_sell_all_bubble.add_theme_font_size_override(
|
||||
"font_size", 11 if compact else 15,
|
||||
)
|
||||
_update_sort_direction_text()
|
||||
_bag_page.size = reference_size
|
||||
_bag_page.position = Vector2.ZERO
|
||||
|
|
@ -2988,11 +2946,7 @@ func _set_content_interactive(interactive: bool) -> void:
|
|||
var detail_interactive: bool = (
|
||||
cooler_interactive and _detail_constellation.visible
|
||||
)
|
||||
for action: NotepadInkActionType in [
|
||||
_favorite_bubble,
|
||||
_sell_bubble,
|
||||
_sell_all_bubble,
|
||||
]:
|
||||
for action: NotepadInkActionType in [_favorite_bubble, _sell_bubble]:
|
||||
var action_interactive: bool = detail_interactive and not action.disabled
|
||||
action.focus_mode = (
|
||||
Control.FOCUS_ALL
|
||||
|
|
@ -3641,11 +3595,6 @@ func _configure_cooler_fish_focus() -> void:
|
|||
not _favorite_bubble.disabled
|
||||
and index + columns >= controls.size()
|
||||
)
|
||||
else control.get_path_to(_sell_all_bubble)
|
||||
if (
|
||||
not _sell_all_bubble.disabled
|
||||
and index + columns >= controls.size()
|
||||
)
|
||||
else control.get_path_to(
|
||||
controls[mini(index + columns, controls.size() - 1)]
|
||||
)
|
||||
|
|
@ -3671,18 +3620,6 @@ func _configure_cooler_fish_focus() -> void:
|
|||
_sell_bubble.get_path_to(_close_button)
|
||||
)
|
||||
_sell_bubble.focus_neighbor_top = _sell_bubble.get_path_to(focused_node)
|
||||
_sell_bubble.focus_neighbor_bottom = (
|
||||
_sell_bubble.get_path_to(_sell_all_bubble)
|
||||
)
|
||||
_sell_all_bubble.focus_neighbor_left = (
|
||||
_sell_all_bubble.get_path_to(_favorite_bubble)
|
||||
)
|
||||
_sell_all_bubble.focus_neighbor_right = (
|
||||
_sell_all_bubble.get_path_to(_close_button)
|
||||
)
|
||||
_sell_all_bubble.focus_neighbor_top = (
|
||||
_sell_all_bubble.get_path_to(_sell_bubble)
|
||||
)
|
||||
|
||||
|
||||
func _compare_catches(left: FishCatchType, right: FishCatchType) -> bool:
|
||||
|
|
@ -3747,7 +3684,6 @@ func _close_detail_constellation() -> void:
|
|||
_sell_bubble.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
_favorite_bubble.refresh_ink_state()
|
||||
_sell_bubble.refresh_ink_state()
|
||||
_refresh_cooler_notepad_action_interactivity()
|
||||
_configure_cooler_fish_focus()
|
||||
|
||||
|
||||
|
|
@ -3814,7 +3750,6 @@ func _update_inventory_detail(fish_catch: FishCatchType) -> void:
|
|||
_sell_bubble.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
_favorite_bubble.refresh_ink_state()
|
||||
_sell_bubble.refresh_ink_state()
|
||||
_refresh_cooler_notepad_action_interactivity()
|
||||
_configure_cooler_fish_focus()
|
||||
return
|
||||
_cooler_detail_texture.texture = fish_catch.fish.display_texture
|
||||
|
|
@ -3862,24 +3797,7 @@ func _update_inventory_detail(fish_catch: FishCatchType) -> void:
|
|||
and not _transitioning
|
||||
and not _page_transitioning
|
||||
)
|
||||
_refresh_cooler_notepad_action_interactivity()
|
||||
_configure_cooler_fish_focus()
|
||||
|
||||
|
||||
func _refresh_cooler_notepad_action_interactivity() -> void:
|
||||
var detail_interactive: bool = (
|
||||
_detail_constellation.visible
|
||||
and _current_section == Section.COOLER
|
||||
and (visible or _shop_cooler_context_active)
|
||||
and not _transitioning
|
||||
and not _page_transitioning
|
||||
and not _sale_confirmation.visible
|
||||
)
|
||||
for action: NotepadInkActionType in [
|
||||
_favorite_bubble,
|
||||
_sell_bubble,
|
||||
_sell_all_bubble,
|
||||
]:
|
||||
for action: NotepadInkActionType in [_favorite_bubble, _sell_bubble]:
|
||||
var action_interactive: bool = detail_interactive and not action.disabled
|
||||
action.focus_mode = (
|
||||
Control.FOCUS_ALL
|
||||
|
|
@ -3892,6 +3810,7 @@ func _refresh_cooler_notepad_action_interactivity() -> void:
|
|||
else Control.MOUSE_FILTER_IGNORE
|
||||
)
|
||||
action.refresh_ink_state()
|
||||
_configure_cooler_fish_focus()
|
||||
|
||||
|
||||
func _update_sale_summary() -> void:
|
||||
|
|
@ -3899,7 +3818,6 @@ func _update_sale_summary() -> void:
|
|||
var buyer_id: StringName = (
|
||||
active_buyer.id if active_buyer != null else StringName()
|
||||
)
|
||||
_update_sell_all_action(active_buyer, buyer_id)
|
||||
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()
|
||||
|
|
@ -4009,55 +3927,6 @@ func _update_sale_summary() -> void:
|
|||
_sale_unavailable.visible = not _sale_unavailable.text.is_empty()
|
||||
|
||||
|
||||
func _update_sell_all_action(
|
||||
active_buyer: FishBuyerProfileType,
|
||||
buyer_id: StringName,
|
||||
) -> void:
|
||||
var sell_all_ids: Array[StringName] = _get_sell_all_catch_ids()
|
||||
var sale_available: bool = (
|
||||
not _sale_in_progress
|
||||
and (
|
||||
_network_sale_service == null
|
||||
or not _network_sale_service.is_local_sale_pending()
|
||||
)
|
||||
and _network_sale_service != null
|
||||
and not buyer_id.is_empty()
|
||||
and _network_sale_service.can_request_sale(buyer_id)
|
||||
and _sale_service != null
|
||||
and active_buyer != null
|
||||
and not sell_all_ids.is_empty()
|
||||
)
|
||||
if sale_available:
|
||||
var preview: FishSaleResultType = _sale_service.preview_batch(
|
||||
sell_all_ids,
|
||||
active_buyer,
|
||||
)
|
||||
sale_available = preview.is_success()
|
||||
_sell_all_bubble.text = "sell all fish"
|
||||
_sell_all_bubble.disabled = not sale_available
|
||||
_sell_all_bubble.persistent_mark = false
|
||||
_sell_all_bubble.refresh_ink_state()
|
||||
|
||||
|
||||
func _get_sell_all_catch_ids() -> Array[StringName]:
|
||||
var catch_ids: Array[StringName] = []
|
||||
if _inventory == null:
|
||||
return catch_ids
|
||||
for fish_catch: FishCatchType in _inventory.get_all_catches():
|
||||
if (
|
||||
fish_catch == null
|
||||
or not fish_catch.is_valid()
|
||||
or fish_catch.is_favorited
|
||||
or (
|
||||
_reservations != null
|
||||
and _reservations.is_fish_reserved(fish_catch.catch_id)
|
||||
)
|
||||
):
|
||||
continue
|
||||
catch_ids.append(fish_catch.catch_id)
|
||||
return catch_ids
|
||||
|
||||
|
||||
func _on_favorite_pressed() -> void:
|
||||
var focused_id: StringName = _fish_selection.get_focused_id()
|
||||
if _inventory == null or focused_id.is_empty():
|
||||
|
|
@ -4082,18 +3951,6 @@ func _on_favorite_pressed() -> void:
|
|||
|
||||
|
||||
func _on_sell_pressed() -> void:
|
||||
_begin_sale_confirmation(_fish_selection.get_selected_ids())
|
||||
|
||||
|
||||
func _on_sell_all_pressed() -> void:
|
||||
var catch_ids: Array[StringName] = _get_sell_all_catch_ids()
|
||||
if catch_ids.is_empty():
|
||||
_transaction_feedback.text = "No sellable fish in the cooler."
|
||||
return
|
||||
_begin_sale_confirmation(catch_ids)
|
||||
|
||||
|
||||
func _begin_sale_confirmation(catch_ids: Array[StringName]) -> void:
|
||||
var active_buyer: FishBuyerProfileType = _get_active_sale_buyer()
|
||||
var buyer_id: StringName = (
|
||||
active_buyer.id if active_buyer != null else StringName()
|
||||
|
|
@ -4116,15 +3973,16 @@ func _begin_sale_confirmation(catch_ids: Array[StringName]) -> void:
|
|||
"Selling is not supported by this server."
|
||||
)
|
||||
return
|
||||
var selected_ids: Array[StringName] = _fish_selection.get_selected_ids()
|
||||
if (
|
||||
_inventory == null
|
||||
or _sale_service == null
|
||||
or active_buyer == null
|
||||
or catch_ids.is_empty()
|
||||
or selected_ids.is_empty()
|
||||
):
|
||||
return
|
||||
var preview: FishSaleResultType = _sale_service.preview_batch(
|
||||
catch_ids,
|
||||
selected_ids,
|
||||
active_buyer
|
||||
)
|
||||
if not preview.is_success():
|
||||
|
|
@ -4136,7 +3994,7 @@ func _begin_sale_confirmation(catch_ids: Array[StringName]) -> void:
|
|||
)
|
||||
_refresh_inventory()
|
||||
return
|
||||
_confirmation_catch_ids = catch_ids.duplicate()
|
||||
_confirmation_catch_ids = selected_ids.duplicate()
|
||||
_confirmation_buyer = active_buyer
|
||||
_confirmation_buyer_id = active_buyer.id
|
||||
_confirmation_generation = _menu_generation
|
||||
|
|
|
|||
|
|
@ -470,16 +470,6 @@ offset_right = 256.0
|
|||
offset_bottom = 464.0
|
||||
text = "sell fish"
|
||||
|
||||
[node name="SellAllBubble" parent="ResponsivePlayerMenuStage/PlayerMenuPresentationScaleRoot/CoolerPage/DetailConstellation" instance=ExtResource("12_ink_action")]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(122, 44)
|
||||
layout_mode = 0
|
||||
offset_left = 78.0
|
||||
offset_top = 426.0
|
||||
offset_right = 200.0
|
||||
offset_bottom = 470.0
|
||||
text = "sell all fish"
|
||||
|
||||
[node name="BagPage" type="Control" parent="ResponsivePlayerMenuStage/PlayerMenuPresentationScaleRoot"]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue