模板脚本文件

This commit is contained in:
2026-09-12 22:18:23 +08:00
parent 2816092fb4
commit d3f1058d79
32 changed files with 3200 additions and 0 deletions
+57
View File
@@ -0,0 +1,57 @@
class_name InventorySlot
extends RefCounted
var item_id: String = ""
var quantity: int = 0
func is_empty() -> bool:
return item_id.is_empty() or quantity <= 0
func add_item(item: Item, amount: int = 1) -> int:
var max_quantity = item.max_stack if item.stackable else 1
if is_empty():
item_id = item.id
quantity = min(amount, max_quantity)
return amount - quantity
if item_id == item.id and item.stackable:
var space_available = item.max_stack - quantity
var amount_to_add = min(amount, space_available)
quantity += amount_to_add
return amount - amount_to_add
return amount
func remove_item(amount: int = 1) -> int:
var removed = min(amount, quantity)
quantity -= removed
if quantity <= 0:
clear()
return removed
func clear() -> void:
item_id = ""
quantity = 0
func to_dict() -> Dictionary:
return {"item_id": item_id, "quantity": quantity}
func from_dict(data: Dictionary) -> void:
item_id = data.get("item_id", "")
quantity = data.get("quantity", 0)
if is_empty():
clear()
return
var item = ItemDatabase.get_item(item_id)
if not item:
clear()
return
var max_quantity = item.max_stack if item.stackable else 1
quantity = clampi(quantity, 1, max_quantity)
+1
View File
@@ -0,0 +1 @@
uid://c7dfwkeylor2j
+27
View File
@@ -0,0 +1,27 @@
class_name Item
extends Resource
enum ItemType { WEAPON, CONSUMABLE, TOOL, MISC, HAT, BACKPACK }
enum ItemRarity { COMMON, UNCOMMON, RARE, EPIC, LEGENDARY }
enum ContextOptions {
DROP,
EQUIP,
UNEQUIP,
}
@export var id: String = ""
@export var name: String = ""
@export var description: String = ""
@export var icon: Texture2D
@export var stackable: bool = true
@export var max_stack: int = 99
@export var item_type: ItemType = ItemType.MISC
@export var rarity: ItemRarity = ItemRarity.COMMON
@export var value: int = 0
@export var context_options: Array[Item.ContextOptions] = []
@export var scene_path: String = ""
+1
View File
@@ -0,0 +1 @@
uid://bbq3lkpgmwr1t
+267
View File
@@ -0,0 +1,267 @@
class_name PlayerInventory
extends RefCounted
const BASE_INVENTORY_SIZE := 16
const BACKPACK_BONUS_SLOTS := 4
const MAX_INVENTORY_SIZE := BASE_INVENTORY_SIZE + BACKPACK_BONUS_SLOTS
var slots: Array[InventorySlot] = []
var equipped_weapon: InventorySlot = InventorySlot.new()
var equipped_hat: InventorySlot = InventorySlot.new()
var equipped_backpack: InventorySlot = InventorySlot.new()
func _init():
_initialize_slots()
func _initialize_slots():
slots.clear()
for i in range(MAX_INVENTORY_SIZE):
slots.append(InventorySlot.new())
func get_active_slot_count() -> int:
return MAX_INVENTORY_SIZE if not equipped_backpack.is_empty() else BASE_INVENTORY_SIZE
func is_slot_active(index: int) -> bool:
return index >= 0 and index < get_active_slot_count()
func get_slot(index: int) -> InventorySlot:
if index >= 0 and index < slots.size():
return slots[index]
return null
func get_equipped_slot(item_type: Item.ItemType) -> InventorySlot:
match item_type:
Item.ItemType.WEAPON:
return equipped_weapon
Item.ItemType.HAT:
return equipped_hat
Item.ItemType.BACKPACK:
return equipped_backpack
_:
return null
func equip_from_slot(index: int, item_type: Item.ItemType) -> bool:
if not is_slot_active(index):
return false
var backpack_slot: InventorySlot = get_slot(index)
var equipped_slot: InventorySlot = get_equipped_slot(item_type)
if not backpack_slot or backpack_slot.is_empty() or not equipped_slot:
return false
var item: Item = ItemDatabase.get_item(backpack_slot.item_id)
if not item or item.item_type != item_type:
return false
var new_item_id: String = backpack_slot.item_id
var new_quantity: int = backpack_slot.quantity
backpack_slot.item_id = equipped_slot.item_id
backpack_slot.quantity = equipped_slot.quantity
equipped_slot.item_id = new_item_id
equipped_slot.quantity = new_quantity
if backpack_slot.is_empty():
backpack_slot.clear()
return true
func unequip_to_slot(item_type: Item.ItemType, destination_index: int = -1) -> bool:
var equipped_slot: InventorySlot = get_equipped_slot(item_type)
if not equipped_slot or equipped_slot.is_empty():
return false
if item_type == Item.ItemType.BACKPACK:
return _unequip_backpack_to_slot(equipped_slot, destination_index)
if destination_index < 0:
destination_index = get_first_empty_slot()
if not is_slot_active(destination_index):
return false
var destination: InventorySlot = get_slot(destination_index)
if not destination or not destination.is_empty():
return false
destination.item_id = equipped_slot.item_id
destination.quantity = equipped_slot.quantity
equipped_slot.clear()
return true
func _unequip_backpack_to_slot(equipped_slot: InventorySlot, destination_index: int) -> bool:
if destination_index < 0:
destination_index = _get_first_empty_base_slot()
if destination_index < 0 or destination_index >= BASE_INVENTORY_SIZE:
return false
var destination := get_slot(destination_index)
if not destination or not destination.is_empty():
return false
var occupied_bonus_slots: Array[int] = []
for i in range(BASE_INVENTORY_SIZE, MAX_INVENTORY_SIZE):
if not slots[i].is_empty():
occupied_bonus_slots.append(i)
var available_base_slots: Array[int] = []
for i in range(BASE_INVENTORY_SIZE):
if i != destination_index and slots[i].is_empty():
available_base_slots.append(i)
if occupied_bonus_slots.size() > available_base_slots.size():
return false
for i in range(occupied_bonus_slots.size()):
var source := slots[occupied_bonus_slots[i]]
var target := slots[available_base_slots[i]]
target.item_id = source.item_id
target.quantity = source.quantity
source.clear()
destination.item_id = equipped_slot.item_id
destination.quantity = equipped_slot.quantity
equipped_slot.clear()
return true
func _get_first_empty_base_slot() -> int:
for i in range(BASE_INVENTORY_SIZE):
if slots[i].is_empty():
return i
return -1
func add_item(item: Item, quantity: int = 1) -> int:
var remaining = quantity
var active_slot_count := get_active_slot_count()
if item.stackable:
for i in range(active_slot_count):
var slot := slots[i]
if slot.item_id == item.id:
remaining = slot.add_item(item, remaining)
if remaining <= 0:
break
if remaining > 0:
for i in range(active_slot_count):
var slot := slots[i]
if slot.is_empty():
remaining = slot.add_item(item, remaining)
if remaining <= 0:
break
return remaining
func remove_item(item_id: String, quantity: int = 1) -> int:
var removed = 0
for i in range(get_active_slot_count()):
var slot := slots[i]
if slot.item_id == item_id:
var slot_removed = slot.remove_item(quantity - removed)
removed += slot_removed
if removed >= quantity:
break
return removed
func move_item(from_index: int, to_index: int, quantity: int = -1) -> bool:
if (
from_index == to_index
or not is_slot_active(from_index)
or not is_slot_active(to_index)
or quantity == 0
or quantity < -1
):
return false
var from_slot = get_slot(from_index)
var to_slot = get_slot(to_index)
if not from_slot or not to_slot or from_slot.is_empty():
return false
var move_amount = from_slot.quantity if quantity == -1 else quantity
move_amount = min(move_amount, from_slot.quantity)
var item = ItemDatabase.get_item(from_slot.item_id)
if not item:
return false
var remaining = to_slot.add_item(item, move_amount)
var moved_amount = move_amount - remaining
if moved_amount > 0:
from_slot.remove_item(moved_amount)
return moved_amount > 0
func swap_items(from_index: int, to_index: int) -> bool:
if not is_slot_active(from_index) or not is_slot_active(to_index):
return false
var from_slot = get_slot(from_index)
var to_slot = get_slot(to_index)
if not from_slot or not to_slot:
return false
if from_slot.item_id == to_slot.item_id and not from_slot.is_empty() and not to_slot.is_empty():
var item = ItemDatabase.get_item(from_slot.item_id)
if item and item.stackable:
var total_quantity = from_slot.quantity + to_slot.quantity
if total_quantity <= item.max_stack:
to_slot.quantity = total_quantity
from_slot.clear()
return true
var space_available = item.max_stack - to_slot.quantity
var amount_to_move = min(space_available, from_slot.quantity)
to_slot.quantity += amount_to_move
from_slot.quantity -= amount_to_move
if from_slot.quantity <= 0:
from_slot.clear()
return true
var temp_item_id = from_slot.item_id
var temp_quantity = from_slot.quantity
from_slot.item_id = to_slot.item_id
from_slot.quantity = to_slot.quantity
to_slot.item_id = temp_item_id
to_slot.quantity = temp_quantity
return true
func get_first_empty_slot() -> int:
for i in range(get_active_slot_count()):
if slots[i].is_empty():
return i
return -1
func to_dict() -> Dictionary:
var data = []
for slot in slots:
data.append(slot.to_dict())
return {
"slots": data,
"equipped_weapon": equipped_weapon.to_dict(),
"equipped_hat": equipped_hat.to_dict(),
"equipped_backpack": equipped_backpack.to_dict()
}
func from_dict(data: Dictionary) -> void:
var slots_data = data.get("slots", [])
for i in range(min(slots_data.size(), slots.size())):
slots[i].from_dict(slots_data[i])
for i in range(slots_data.size(), slots.size()):
slots[i].clear()
equipped_weapon.from_dict(data.get("equipped_weapon", {}))
equipped_hat.from_dict(data.get("equipped_hat", {}))
equipped_backpack.from_dict(data.get("equipped_backpack", {}))
@@ -0,0 +1 @@
uid://dncl3vbyhhee3