feat: add persistent inventory storage slots
This commit is contained in:
parent
6db6fbba7f
commit
a88e76848b
13 changed files with 875 additions and 65 deletions
67
tests/inventory_storage_persistence_validation.gd
Normal file
67
tests/inventory_storage_persistence_validation.gd
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
extends SceneTree
|
||||
|
||||
const MainScene: PackedScene = preload("res://main/main.tscn")
|
||||
|
||||
|
||||
func _initialize() -> void:
|
||||
call_deferred("_run")
|
||||
|
||||
|
||||
func _run() -> void:
|
||||
root.size = Vector2i(1280, 720)
|
||||
var main: Node = MainScene.instantiate()
|
||||
root.add_child(main)
|
||||
for _frame: int in 4:
|
||||
await process_frame
|
||||
if not bool(main.get("_application_initialized")):
|
||||
main.call("_activate_selected_data_path", "", true)
|
||||
for _frame: int in 8:
|
||||
await process_frame
|
||||
assert(bool(main.get("_application_initialized")))
|
||||
|
||||
var save_manager := main.get("_save_manager") as PlayerSaveManager
|
||||
var player := main.get("_player") as Player
|
||||
assert(save_manager != null and player != null)
|
||||
assert(save_manager.initialize_new_game())
|
||||
save_manager.set_autosave_enabled(true)
|
||||
assert(player.bag.add_item(&"art_kit"))
|
||||
assert(player.bag.add_item(&"coffee"))
|
||||
assert(player.bag.move_item_to_storage_slot(&"basic_fishing_rod", 14))
|
||||
assert(player.bag.move_item_to_storage_slot(&"coffee", 12))
|
||||
assert(save_manager.save_now())
|
||||
|
||||
var save_file := FileAccess.open(
|
||||
str(save_manager.get("_save_path")),
|
||||
FileAccess.READ,
|
||||
)
|
||||
assert(save_file != null)
|
||||
var parsed: Variant = JSON.parse_string(save_file.get_as_text())
|
||||
save_file.close()
|
||||
assert(typeof(parsed) == TYPE_DICTIONARY)
|
||||
var records: Array = (parsed as Dictionary)["bag"]["items"]
|
||||
assert(_saved_slot(records, &"basic_fishing_rod") == 14)
|
||||
assert(_saved_slot(records, &"coffee") == 12)
|
||||
|
||||
assert(player.bag.move_item_to_storage_slot(&"basic_fishing_rod", 0))
|
||||
assert(player.bag.move_item_to_storage_slot(&"coffee", 0))
|
||||
assert(save_manager.load_player_data())
|
||||
assert(player.bag.get_storage_slot(&"basic_fishing_rod") == 14)
|
||||
assert(player.bag.get_storage_slot(&"coffee") == 12)
|
||||
|
||||
main.queue_free()
|
||||
for _frame: int in 4:
|
||||
await process_frame
|
||||
await create_timer(0.1).timeout
|
||||
print("Inventory storage persistence validation: PASS")
|
||||
quit()
|
||||
|
||||
|
||||
func _saved_slot(records: Array, item_id: StringName) -> int:
|
||||
for value: Variant in records:
|
||||
if (
|
||||
typeof(value) == TYPE_DICTIONARY
|
||||
and str((value as Dictionary).get("item_id", ""))
|
||||
== String(item_id)
|
||||
):
|
||||
return int((value as Dictionary).get("storage_slot", -1))
|
||||
return -1
|
||||
1
tests/inventory_storage_persistence_validation.gd.uid
Normal file
1
tests/inventory_storage_persistence_validation.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://bwp2jhs116hmw
|
||||
172
tests/inventory_storage_validation.gd
Normal file
172
tests/inventory_storage_validation.gd
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
extends SceneTree
|
||||
|
||||
const BagItemSpriteType = preload(
|
||||
"res://ui/components/bubble_menu/bag_item_sprite.gd"
|
||||
)
|
||||
const BagStorageSlotType = preload(
|
||||
"res://ui/components/bubble_menu/bag_storage_slot.gd"
|
||||
)
|
||||
const Catalog: ItemCatalog = preload(
|
||||
"res://items/catalog/item_catalog.tres"
|
||||
)
|
||||
const OwnedItemType = preload("res://items/owned_item.gd")
|
||||
const PlayerBagType = preload("res://inventory/player_bag.gd")
|
||||
const PlayerHotbarType = preload("res://inventory/player_hotbar.gd")
|
||||
const PlayerMenuScene = preload("res://ui/player_menu.tscn")
|
||||
const PlayerMenuType = preload("res://ui/player_menu.gd")
|
||||
|
||||
const EQUIPMENT_IDS: Array[StringName] = [
|
||||
&"basic_fishing_rod",
|
||||
&"art_kit",
|
||||
&"crab_net",
|
||||
&"magnet",
|
||||
]
|
||||
const ITEM_IDS: Array[StringName] = [
|
||||
&"coffee",
|
||||
&"energy_drink",
|
||||
&"snack",
|
||||
]
|
||||
|
||||
|
||||
func _initialize() -> void:
|
||||
call_deferred("_run")
|
||||
|
||||
|
||||
func _run() -> void:
|
||||
root.size = Vector2i(1280, 720)
|
||||
var bag := PlayerBagType.new()
|
||||
bag.setup(Catalog)
|
||||
for item_id: StringName in EQUIPMENT_IDS + ITEM_IDS:
|
||||
assert(bag.add_item(item_id))
|
||||
for index: int in EQUIPMENT_IDS.size():
|
||||
assert(bag.get_storage_slot(EQUIPMENT_IDS[index]) == index)
|
||||
for index: int in ITEM_IDS.size():
|
||||
assert(bag.get_storage_slot(ITEM_IDS[index]) == index)
|
||||
|
||||
assert(bag.move_item_to_storage_slot(&"basic_fishing_rod", 14))
|
||||
assert(bag.get_storage_slot(&"basic_fishing_rod") == 14)
|
||||
assert(bag.move_item_to_storage_slot(&"crab_net", 14))
|
||||
assert(bag.get_storage_slot(&"crab_net") == 14)
|
||||
assert(bag.get_storage_slot(&"basic_fishing_rod") == 2)
|
||||
var saved_record: Dictionary = bag.get_owned_item(
|
||||
&"crab_net"
|
||||
).to_save_dict()
|
||||
assert(int(saved_record.get("storage_slot", -1)) == 14)
|
||||
|
||||
var legacy_equipment := OwnedItemType.new()
|
||||
legacy_equipment.item_id = &"basic_fishing_rod"
|
||||
var legacy_item := OwnedItemType.new()
|
||||
legacy_item.item_id = &"coffee"
|
||||
var legacy_records: Array[OwnedItemType] = [
|
||||
legacy_equipment,
|
||||
legacy_item,
|
||||
]
|
||||
var legacy_bag := PlayerBagType.new()
|
||||
legacy_bag.setup(Catalog)
|
||||
assert(legacy_bag.replace_all_items(legacy_records))
|
||||
assert(legacy_bag.get_storage_slot(&"basic_fishing_rod") == 0)
|
||||
assert(legacy_bag.get_storage_slot(&"coffee") == 0)
|
||||
legacy_bag.free()
|
||||
|
||||
var menu := PlayerMenuScene.instantiate() as PlayerMenu
|
||||
root.add_child(menu)
|
||||
await process_frame
|
||||
menu.set("_bag", bag)
|
||||
var hotbar := PlayerHotbarType.new()
|
||||
hotbar.setup(bag, Catalog)
|
||||
menu.set("_hotbar", hotbar)
|
||||
menu.set("_item_catalog", Catalog)
|
||||
menu.set("_bag_view", PlayerMenuType.BagView.EQUIPMENT)
|
||||
menu.visible = true
|
||||
menu.call("_show_section_immediate", PlayerMenuType.Section.BAG)
|
||||
menu.call("_set_content_interactive", true)
|
||||
menu.call("_refresh_bag")
|
||||
await process_frame
|
||||
_validate_grid(menu, EQUIPMENT_IDS.size())
|
||||
|
||||
var item_nodes: Dictionary = menu.get("_bag_item_nodes")
|
||||
var crab_node := item_nodes.get(&"crab_net") as BagItemSpriteType
|
||||
assert(crab_node != null)
|
||||
menu.set(
|
||||
"_controller_ownership",
|
||||
PlayerMenuType.ControllerOwnership.ITEM_LIST,
|
||||
)
|
||||
menu.call("_apply_inventory_controller_zone_focus_modes")
|
||||
crab_node.grab_focus()
|
||||
assert(bool(menu.call("_try_begin_controller_storage_placement")))
|
||||
await process_frame
|
||||
assert(
|
||||
menu.get("_controller_ownership")
|
||||
== PlayerMenuType.ControllerOwnership.STORAGE_PLACEMENT
|
||||
)
|
||||
var slots: Array = menu.get("_bag_slot_nodes")
|
||||
var bottom_slot := slots[12] as BagStorageSlotType
|
||||
bottom_slot.grab_focus()
|
||||
var down := InputEventAction.new()
|
||||
down.action = &"ui_down"
|
||||
down.pressed = true
|
||||
assert(bool(menu.call("_handle_controller_ownership_input", down)))
|
||||
assert(
|
||||
menu.get("_controller_ownership")
|
||||
== PlayerMenuType.ControllerOwnership.HOTBAR_PLACEMENT
|
||||
)
|
||||
var up := InputEventAction.new()
|
||||
up.action = &"ui_up"
|
||||
up.pressed = true
|
||||
assert(bool(menu.call("_handle_controller_ownership_input", up)))
|
||||
assert(
|
||||
menu.get("_controller_ownership")
|
||||
== PlayerMenuType.ControllerOwnership.STORAGE_PLACEMENT
|
||||
)
|
||||
await process_frame
|
||||
assert(root.gui_get_focus_owner() == bottom_slot)
|
||||
assert(StringName(menu.get("_controller_storage_identity")) == &"crab_net")
|
||||
var target_slot := slots[7] as BagStorageSlotType
|
||||
target_slot.grab_focus()
|
||||
menu.call("_confirm_controller_storage_placement")
|
||||
await process_frame
|
||||
assert(bag.get_storage_slot(&"crab_net") == 7)
|
||||
assert(
|
||||
menu.get("_controller_ownership")
|
||||
== PlayerMenuType.ControllerOwnership.ITEM_LIST
|
||||
)
|
||||
|
||||
menu.call("_show_bag_view", PlayerMenuType.BagView.CONSUMABLES)
|
||||
await process_frame
|
||||
_validate_grid(menu, ITEM_IDS.size())
|
||||
menu.call("_on_bag_item_dropped", &"coffee", 12)
|
||||
await process_frame
|
||||
assert(bag.get_storage_slot(&"coffee") == 12)
|
||||
|
||||
menu.queue_free()
|
||||
hotbar.free()
|
||||
bag.free()
|
||||
await process_frame
|
||||
print("Inventory storage validation: PASS")
|
||||
quit()
|
||||
|
||||
|
||||
func _validate_grid(menu: PlayerMenu, expected_items: int) -> void:
|
||||
var slots: Array = menu.get("_bag_slot_nodes")
|
||||
assert(slots.size() == PlayerBagType.MIN_STORAGE_SLOT_COUNT)
|
||||
var seen_positions: Dictionary[Vector2, bool] = {}
|
||||
for index: int in slots.size():
|
||||
var slot := slots[index] as BagStorageSlotType
|
||||
assert(slot != null)
|
||||
assert(slot.storage_slot_index == index)
|
||||
assert(not seen_positions.has(slot.position))
|
||||
seen_positions[slot.position] = true
|
||||
var normal := slot.get_theme_stylebox("normal") as StyleBoxFlat
|
||||
assert(normal != null)
|
||||
assert(normal.bg_color.a >= 0.7)
|
||||
assert((slots[1] as Control).position.x > (slots[0] as Control).position.x)
|
||||
assert((slots[5] as Control).position.y > (slots[0] as Control).position.y)
|
||||
var item_nodes := menu.get("_bag_item_nodes") as Dictionary
|
||||
assert(
|
||||
item_nodes.size() == expected_items,
|
||||
"expected %d visible bag items, found %d: %s" % [
|
||||
expected_items,
|
||||
item_nodes.size(),
|
||||
str(item_nodes.keys()),
|
||||
],
|
||||
)
|
||||
1
tests/inventory_storage_validation.gd.uid
Normal file
1
tests/inventory_storage_validation.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://w6e06q8yfwp6
|
||||
50
tests/tackle_order_validation.gd
Normal file
50
tests/tackle_order_validation.gd
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
extends SceneTree
|
||||
|
||||
const Catalog: ItemCatalog = preload("res://items/catalog/item_catalog.tres")
|
||||
const PlayerMenuType = preload("res://ui/player_menu.gd")
|
||||
|
||||
const EXPECTED_BAIT_ORDER: Array[StringName] = [
|
||||
&"worms",
|
||||
&"snails",
|
||||
&"shrimp",
|
||||
&"squid_chunks",
|
||||
&"whole_sardine",
|
||||
&"whole_anchovy",
|
||||
&"luminous_roe",
|
||||
]
|
||||
|
||||
|
||||
func _initialize() -> void:
|
||||
call_deferred("_run")
|
||||
|
||||
|
||||
func _run() -> void:
|
||||
var player_menu := PlayerMenuType.new() as PlayerMenu
|
||||
player_menu.set("_item_catalog", Catalog)
|
||||
var tackle_items: Array[OwnedItem] = []
|
||||
for item_id: StringName in [
|
||||
&"luminous_roe",
|
||||
&"whole_anchovy",
|
||||
&"shrimp",
|
||||
&"snails",
|
||||
&"whole_sardine",
|
||||
&"squid_chunks",
|
||||
&"worms",
|
||||
]:
|
||||
var owned := OwnedItem.new()
|
||||
owned.item_id = item_id
|
||||
owned.quantity = 1
|
||||
tackle_items.append(owned)
|
||||
tackle_items.sort_custom(
|
||||
func(first: OwnedItem, second: OwnedItem) -> bool:
|
||||
return bool(player_menu.call(
|
||||
"_sort_tackle_items", first, second
|
||||
))
|
||||
)
|
||||
var sorted_ids: Array[StringName] = []
|
||||
for owned: OwnedItem in tackle_items:
|
||||
sorted_ids.append(owned.item_id)
|
||||
assert(sorted_ids == EXPECTED_BAIT_ORDER)
|
||||
player_menu.free()
|
||||
print("Tackle order validation: PASS")
|
||||
quit()
|
||||
1
tests/tackle_order_validation.gd.uid
Normal file
1
tests/tackle_order_validation.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://27tkdvxgkv3y
|
||||
Loading…
Add table
Add a link
Reference in a new issue