started working on spellbook

This commit is contained in:
2026-02-08 16:48:21 +01:00
parent 9e2516a5ab
commit 82219474ec
28 changed files with 2009 additions and 151 deletions

View File

@@ -37,6 +37,11 @@ var equipment_selection_index: int = 0 # Current equipment slot index (0-5: main
@onready var sfx_potion: AudioStreamPlayer2D = $SfxPotion
@onready var sfx_food: AudioStreamPlayer2D = $SfxFood
@onready var sfx_armour: AudioStreamPlayer2D = $SfxArmour
@onready var tab_row: HBoxContainer = $InventoryContainer/MarginContainer/MarginContainer/VBoxContainer/TabRow
@onready var inventory_tab_btn: Button = $InventoryContainer/MarginContainer/MarginContainer/VBoxContainer/TabRow/InventoryTab
@onready var spell_book_tab_btn: Button = $InventoryContainer/MarginContainer/MarginContainer/VBoxContainer/TabRow/SpellBookTab
@onready var spell_book_panel: Control = $InventoryContainer/MarginContainer/MarginContainer/VBoxContainer/SpellBookPanel
@onready var inventory_hbox: HBoxContainer = $InventoryContainer/MarginContainer/MarginContainer/VBoxContainer/HBox
# Bar layout constants (align X/Y + bar across rows)
const _BAR_WIDTH: int = 100
@@ -114,6 +119,9 @@ var quantity_font: Font = null
# Selection animation
var selection_animation_time: float = 0.0
# Tab: "inventory" or "spell_book"
var _current_tab: String = "inventory"
func _ready():
# Set layer to be above game but below chat
layer = 150
@@ -137,6 +145,12 @@ func _ready():
# Setup selection rectangle (already in scene, just configure it)
_setup_selection_rectangle()
# Spell Book / Inventory tabs
if inventory_tab_btn:
inventory_tab_btn.pressed.connect(_on_inventory_tab_pressed)
if spell_book_tab_btn:
spell_book_tab_btn.pressed.connect(_on_spell_book_tab_pressed)
# Find local player
call_deferred("_find_local_player")
@@ -1113,7 +1127,16 @@ func _format_item_info(item: Item) -> String:
text += "\n\n"
# Controls
if item.item_type == Item.ItemType.Equippable:
if item.weapon_type == Item.WeaponType.SPELLBOOK:
if local_player and local_player.character_stats:
var spell_id = local_player.character_stats._tome_to_spell_id(item) if local_player.character_stats.has_method("_tome_to_spell_id") else ""
if spell_id != "" and spell_id in local_player.character_stats.learnt_spells:
text += "Already learnt."
else:
text += "Press F to learn spell"
else:
text += "Press F to learn spell"
elif item.item_type == Item.ItemType.Equippable:
if selected_type == "equipment":
text += "Press F to unequip"
else:
@@ -1445,6 +1468,13 @@ func _input(event):
if not is_open:
return
# B key: switch to Spell Book tab when inventory is open
if event is InputEventKey and event.keycode == KEY_B and event.pressed and not event.echo:
_current_tab = "spell_book" if _current_tab == "inventory" else "inventory"
_apply_tab_visibility()
get_viewport().set_input_as_handled()
return
# Arrow key navigation (use ui_left/right/up/down so keybindings work)
var direction = ""
var skip_repeat = event is InputEventKey and event.echo
@@ -1457,7 +1487,9 @@ func _input(event):
elif not skip_repeat and event.is_action_pressed("ui_down"):
direction = "down"
if direction != "":
if selected_type == "level_up_stat":
if _current_tab == "spell_book":
pass
elif selected_type == "level_up_stat":
_navigate_level_up_stats(direction)
elif selected_type == "equipment":
_navigate_equipment(direction)
@@ -1499,6 +1531,16 @@ func _handle_f_key():
if selected_type == "equipment" and selected_slot != "":
var equipped_item = char_stats.equipment[selected_slot]
if equipped_item:
# Tome in offhand: use (F) to learn spell and consume tome
if equipped_item.weapon_type == Item.WeaponType.SPELLBOOK and char_stats.has_method("learn_spell_from_tome"):
if char_stats.learn_spell_from_tome(equipped_item):
_update_ui()
_update_selection_from_navigation()
_update_selection_rectangle()
_update_info_panel()
if sfx_armour:
sfx_armour.play()
return
char_stats.unequip_item(equipped_item)
# Play armour sound when unequipping
if sfx_armour:
@@ -1540,6 +1582,23 @@ func _handle_f_key():
return
if selected_type == "item" and selected_item:
# Tome in inventory: use (F) to learn spell and consume tome
if selected_item.weapon_type == Item.WeaponType.SPELLBOOK and char_stats.has_method("learn_spell_from_tome"):
if char_stats.learn_spell_from_tome(selected_item):
var current_item_index = inventory_selection_row * 8 + inventory_selection_col
_update_ui()
if current_item_index < char_stats.inventory.size():
inventory_selection_row = current_item_index / 8
inventory_selection_col = current_item_index % 8
elif char_stats.inventory.size() > 0:
inventory_selection_row = 0
inventory_selection_col = 0
_update_selection_from_navigation()
_update_selection_rectangle()
_update_info_panel()
if sfx_armour:
sfx_armour.play()
return
if selected_item.item_type == Item.ItemType.Equippable and selected_item.equipment_type != Item.EquipmentType.NONE:
# Remember which slot the item will be equipped to
var target_slot_name = ""
@@ -1820,6 +1879,7 @@ func _open_inventory():
_update_ui()
_update_stats()
_apply_tab_visibility()
if not local_player:
_find_local_player()
@@ -1841,6 +1901,37 @@ func _close_inventory():
_lock_player_controls(false)
func _on_inventory_tab_pressed():
_current_tab = "inventory"
# Reset selection so first item gets selected (same as TAB-open flow)
selected_type = ""
selected_item = null
selected_slot = ""
inventory_selection_row = 0
inventory_selection_col = 0
_apply_tab_visibility()
_update_ui()
func _on_spell_book_tab_pressed():
_current_tab = "spell_book"
_apply_tab_visibility()
func _apply_tab_visibility():
var show_inv = (_current_tab == "inventory")
if inventory_hbox:
inventory_hbox.visible = show_inv
if spell_book_panel:
spell_book_panel.visible = not show_inv
if not show_inv and spell_book_panel.has_method("set_character_stats"):
if local_player and local_player.character_stats:
spell_book_panel.set_character_stats(local_player.character_stats)
if spell_book_panel.has_method("refresh"):
spell_book_panel.refresh()
if selection_rectangle:
selection_rectangle.visible = show_inv
if info_panel:
info_panel.visible = show_inv
func _lock_player_controls(lock: bool):
var game_world = get_tree().get_first_node_in_group("game_world")
if game_world: