diff --git a/data/items/item.gd b/data/items/item.gd index 3d8d4a4..59127b8 100644 --- a/data/items/item.gd +++ b/data/items/item.gd @@ -2,4 +2,7 @@ class_name Item extends Resource @export var image : Texture2D +@export var name : StringName @export var brief : String +@export var quantity : int = 1 +@export var max_quantity : int = 1 diff --git a/external/test-qsvchar.clip b/external/test-qsvchar.clip index 2194679..750e71a 100644 Binary files a/external/test-qsvchar.clip and b/external/test-qsvchar.clip differ diff --git a/scripts/adventurer.gd b/scripts/adventurer.gd index 4c630e3..6040421 100644 --- a/scripts/adventurer.gd +++ b/scripts/adventurer.gd @@ -25,9 +25,14 @@ var armor : Armor var accessory : Accessory var inventory : Dictionary[Vector2, Item] = {} var inventory_size : Vector2i = Vector2i(6,1) +var inventory_count : int = 0 var quest_sprite : QuestSprite +signal changed() +signal levelled() +signal died() + func _init() -> void: stats = StatBlock.new() @@ -45,10 +50,12 @@ func generate() -> void: max_energy = stats.INT * 10 + stats.FAI * 10 life = max_life energy = max_energy + changed.emit() func assign_quest(quest : Quest) -> void: self.quest = quest quest.initiate(self) + changed.emit() func full_name() -> String: return given_name + " " + surname @@ -57,18 +64,65 @@ func gain_level() -> void: level += 1 #TODO: Make stats improve based on job Game.notice("%s has reached level %d!" % [full_name(), level]) + #TODO: Make Sideview display level up + changed.emit() + levelled.emit() func gain_exp(amount : int) -> void: exp += amount while exp >= get_tnl(): exp -= get_tnl() gain_level() + changed.emit() func gain_gold(amount :int) -> void: gold += amount + changed.emit() func get_tnl() -> int: if job: return job.get_tnl(level) else: return level * 10 + +func find_open_inventory_slot(item : Item) -> Vector2: + var first_open : Vector2 = Vector2(-1,-1) + for j in range(inventory_size.y): + for i in range(inventory_size.x): + var curr_slot : Item = inventory.get(Vector2(i,j)) + if curr_slot != null: + #TODO: Figure out how to handle split stacking later? + if curr_slot.name == item.name and curr_slot.max_quantity < curr_slot.quantity + item.quantity: + return Vector2(i,j) + elif first_open == Vector2(-1,-1): + first_open = Vector2(i,j) + return first_open + +func try_pickup_item(item : Item) -> bool: + if inventory_count >= inventory_size.x * inventory_size.y: + return false + pickup_item(item) + return true + +func pickup_item(item : Item) -> void: + var open_slot = find_open_inventory_slot(item) + if inventory.has(open_slot): + inventory[open_slot].quantity += item.quantity + else: + if inventory_count >= inventory_size.x * inventory_size.y: + printerr("Cannot fit additional item!") + inventory[open_slot] = item + inventory_count+=1 + changed.emit() + +func move_item(from : Vector2, to: Vector2) -> void: + if !inventory.has(from): + printerr("Cannot move item from %s to %s, %s is empty!" % [from, to, from]) + var itm = inventory[from] + if inventory.has(to): + var itm2 = inventory[to] + inventory[from] = itm2 + else: + inventory.erase(from) + inventory[to] = itm + changed.emit() diff --git a/scripts/adventurer_profile_window.gd b/scripts/adventurer_profile_window.gd index 45cb683..f439afa 100644 --- a/scripts/adventurer_profile_window.gd +++ b/scripts/adventurer_profile_window.gd @@ -15,9 +15,19 @@ var data : Adventurer @onready var faiLabel :Label = %FAILabel @onready var lukLabel :Label = %LUKLabel +var item_slots : Array[ItemSlot] func setup(adv : Adventurer) -> void: data = adv + data.changed.connect(_on_data_changed) + update_stats() + item_slots = [] + for child : ItemSlot in %InventoryGrid.get_children(): + item_slots.append(child) + #TODO: Show equipment + update_items() + +func update_stats() -> void: nameLabel.text = data.full_name() if data.job: jobLabel.text = data.job.name @@ -33,8 +43,21 @@ func setup(adv : Adventurer) -> void: chaLabel.text = str(data.stats.CHA) faiLabel.text = str(data.stats.FAI) lukLabel.text = str(data.stats.LUK) - #TODO: Show equipment - populate_items() -func populate_items() -> void: - pass +func update_items() -> void: + var isize = data.inventory_size.x * data.inventory_size.y + var islots = len(item_slots) + %InventoryGrid.columns = data.inventory_size.x + for crd in data.inventory.keys(): + var idx = crd.y * data.inventory_size.x + crd.x + var item = data.inventory[crd] + item_slots[idx].update(item) + item_slots[idx].visible = true + + for idx in range(isize, islots): + item_slots[idx].visible = false + + +func _on_data_changed() -> void: + update_stats() + update_items() diff --git a/scripts/item_display_window.gd b/scripts/item_display_window.gd new file mode 100644 index 0000000..d248fb8 --- /dev/null +++ b/scripts/item_display_window.gd @@ -0,0 +1 @@ +extends Window diff --git a/scripts/item_display_window.gd.uid b/scripts/item_display_window.gd.uid new file mode 100644 index 0000000..7d1ce04 --- /dev/null +++ b/scripts/item_display_window.gd.uid @@ -0,0 +1 @@ +uid://cpiucydmov1qj diff --git a/scripts/item_slot.gd b/scripts/item_slot.gd index 8b0ac90..703b022 100644 --- a/scripts/item_slot.gd +++ b/scripts/item_slot.gd @@ -7,14 +7,25 @@ var item : Item @onready var item_sprite : TextureRect = $Item func assign(itm : Item) -> void: - item = item - item_sprite.texture = item.image + item = itm + if item.image != null: + item_sprite.texture = item.image func swap(item_slot : ItemSlot) -> void: var itm = item assign(itm) item_slot.assign(itm) +func update(itm : Item) -> void: + if itm == null: + clear() + elif itm != item: + assign(itm) + +func clear() -> void: + item = null + item_sprite.texture = null + func _on_gui_input(event: InputEvent) -> void: var mmevt = event as InputEventMouseMotion var mbevt = event as InputEventMouseButton diff --git a/scripts/player.gd b/scripts/player.gd index cf09097..fa1b513 100644 --- a/scripts/player.gd +++ b/scripts/player.gd @@ -12,6 +12,7 @@ var data : Adventurer func _ready() -> void: Game.player = self data = Adventurer.new() + data.inventory_size = Vector2(4,2) data.name = "Player" setup.call_deferred() diff --git a/scripts/test_scene.gd b/scripts/test_scene.gd index dc81725..08477d5 100644 --- a/scripts/test_scene.gd +++ b/scripts/test_scene.gd @@ -1,6 +1,6 @@ extends Node2D var test_adv = preload("res://templates/test_adventurer.tscn") - +var test_item = preload("res://data/items/pitchfork.tres") @onready var door_player : AudioStreamPlayer = $AudioStreamPlayer func _ready() -> void: #var adv : Adventurer = test_adv.instantiate() as Adventurer @@ -13,6 +13,9 @@ func _ready() -> void: quest.events.append(evt) Guild.add_quest(quest) Guild.assign_quest(Game.player.data, quest) + var itm = test_item.duplicate() + Game.player.data.pickup_item(itm) + Game.player.data.move_item(Vector2(0,0), Vector2(1,0)) #Game.end_shift() #var tween = create_tween() #tween.tween_interval(3) diff --git a/templates/item_display_window.tscn b/templates/item_display_window.tscn new file mode 100644 index 0000000..9da8925 --- /dev/null +++ b/templates/item_display_window.tscn @@ -0,0 +1,78 @@ +[gd_scene load_steps=4 format=3 uid="uid://dggjyxoa33r7y"] + +[ext_resource type="Script" uid="uid://cpiucydmov1qj" path="res://scripts/item_display_window.gd" id="1_n2g4t"] +[ext_resource type="Texture2D" uid="uid://cjjtgrr56guj0" path="res://graphics/ui/item-slot.png" id="2_dxjvd"] +[ext_resource type="Texture2D" uid="uid://clrvwaqb61lpv" path="res://graphics/items/pitchfork.png" id="3_tsl8r"] + +[node name="Item Display Window" type="Window"] +oversampling_override = 1.0 +size = Vector2i(300, 300) +borderless = true +popup_window = true +script = ExtResource("1_n2g4t") + +[node name="Panel" type="PanelContainer" parent="."] +custom_minimum_size = Vector2(300, 300) +anchors_preset = -1 +offset_right = 300.0 +offset_bottom = 300.0 + +[node name="MarginContainer" type="MarginContainer" parent="Panel"] +layout_mode = 2 +theme_override_constants/margin_left = 2 +theme_override_constants/margin_top = 2 +theme_override_constants/margin_right = 0 +theme_override_constants/margin_bottom = 0 + +[node name="VBoxContainer" type="VBoxContainer" parent="Panel/MarginContainer"] +layout_mode = 2 + +[node name="HBoxContainer" type="HBoxContainer" parent="Panel/MarginContainer/VBoxContainer"] +layout_mode = 2 + +[node name="MarginContainer" type="CenterContainer" parent="Panel/MarginContainer/VBoxContainer/HBoxContainer"] +custom_minimum_size = Vector2(71, 71) +layout_mode = 2 + +[node name="TextureRect2" type="TextureRect" parent="Panel/MarginContainer/VBoxContainer/HBoxContainer/MarginContainer"] +custom_minimum_size = Vector2(71, 71) +layout_mode = 2 +texture = ExtResource("2_dxjvd") + +[node name="TextureRect" type="TextureRect" parent="Panel/MarginContainer/VBoxContainer/HBoxContainer/MarginContainer"] +layout_mode = 2 +texture = ExtResource("3_tsl8r") +stretch_mode = 3 + +[node name="VBoxContainer" type="VBoxContainer" parent="Panel/MarginContainer/VBoxContainer/HBoxContainer"] +layout_mode = 2 +theme_override_constants/separation = 0 + +[node name="Label" type="Label" parent="Panel/MarginContainer/VBoxContainer/HBoxContainer/VBoxContainer"] +layout_mode = 2 +text = "ITEM NAME" + +[node name="Label2" type="Label" parent="Panel/MarginContainer/VBoxContainer/HBoxContainer/VBoxContainer"] +layout_mode = 2 +text = "ITEM TYPE" + +[node name="Label3" type="Label" parent="Panel/MarginContainer/VBoxContainer/HBoxContainer/VBoxContainer"] +layout_mode = 2 +text = "ITEM GRADE" + +[node name="Label2" type="Label" parent="Panel/MarginContainer/VBoxContainer"] +layout_mode = 2 +text = "Primary Stat Goes Here" + +[node name="Label3" type="Label" parent="Panel/MarginContainer/VBoxContainer"] +custom_minimum_size = Vector2(0, 60) +layout_mode = 2 +text = "Secondary Stats Go Here" + +[node name="HSeparator" type="HSeparator" parent="Panel/MarginContainer/VBoxContainer"] +layout_mode = 2 + +[node name="Label" type="Label" parent="Panel/MarginContainer/VBoxContainer"] +custom_minimum_size = Vector2(0, 150) +layout_mode = 2 +text = "Brief Description Goes Here" diff --git a/templates/player_profile_window.tscn b/templates/player_profile_window.tscn index d60b8b2..0ea32da 100644 --- a/templates/player_profile_window.tscn +++ b/templates/player_profile_window.tscn @@ -522,6 +522,7 @@ offset_bottom = 509.0 texture = ExtResource("10_rldp4") [node name="InventoryGrid" type="GridContainer" parent="."] +unique_name_in_owner = true anchors_preset = -1 offset_left = 325.0 offset_top = 513.0