Compare commits
26 Commits
56710afc12
...
sugary-pan
| Author | SHA1 | Date | |
|---|---|---|---|
| 291d911a50 | |||
| 67c91a37b0 | |||
| cec36b7aec | |||
| 7c36d9ff55 | |||
| 91f4b1d8d5 | |||
| 870e3a6ff7 | |||
| d039c996d1 | |||
| eadbd636ac | |||
| d2b1f4ab3d | |||
| 7601c87600 | |||
| a54fe6652f | |||
| cebd53ae8e | |||
| 81feaa4f4f | |||
| efc2b2249c | |||
| b3bad1d0e6 | |||
| a9ec2e6893 | |||
| 378bcdda47 | |||
| d94912bb79 | |||
| 92866d5fc8 | |||
| 9ed55d6345 | |||
| c115810425 | |||
| e905a8adda | |||
| fb8798a4ae | |||
| afcf92dbfd | |||
| dee6216873 | |||
| a0afc9bd1f |
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -1,3 +1,6 @@
|
|||||||
[submodule "kq4-sierra-decompile"]
|
[submodule "kq4-sierra-decompile"]
|
||||||
path = kq4-sierra-decompile
|
path = kq4-sierra-decompile
|
||||||
url = ssh://raspberrypi/~/git/sierra-decompile
|
url = ssh://raspberrypi/~/git/sierra-decompile
|
||||||
|
[submodule "godot-mcp"]
|
||||||
|
path = godot-mcp
|
||||||
|
url = https://github.com/tugcantopaloglu/godot-mcp
|
||||||
|
|||||||
@@ -0,0 +1,89 @@
|
|||||||
|
---
|
||||||
|
## Goal
|
||||||
|
- Implement inventory and backpack system in Godot 4.6 point-and-click adventure game per plan at `docs/plans/2026-04-26-001-feat-inventory-backpack-system-plan.md`
|
||||||
|
|
||||||
|
## Constraints & Preferences
|
||||||
|
- Interaction handlers are signals emitted by items, not embedded dictionary data
|
||||||
|
- No multi-step transition queues — FSM transitions interrupt in-flight animations immediately
|
||||||
|
- No sound required
|
||||||
|
- Item cursor as 5th `ActionState` slot (`ITEM`, value 4); right-click cycles WALK→LOOK→TOUCH→TALK→ITEM→WALK
|
||||||
|
- Use colored `ColorRect` boxes as placeholders for all item/backpack visuals
|
||||||
|
- Follow PRD §13 recommended Godot architecture approaches
|
||||||
|
- PRD is engine-agnostic but implementation targets Godot 4.6
|
||||||
|
|
||||||
|
## Progress
|
||||||
|
### Done
|
||||||
|
- Read and analyzed `inventory-prd.md` (791 lines)
|
||||||
|
- Researched existing codebase patterns
|
||||||
|
- Wrote complete plan to `docs/plans/2026-04-26-001-feat-inventory-backpack-system-plan.md` with 6 implementation units
|
||||||
|
- Applied 5 user edits to plan: signal-based interactions, no transition queues, no sound, ActionState ITEM slot, colored boxes
|
||||||
|
- Created directory structure: `inventory/inventory_backpack/`, `inventory/inventory_overlay/`
|
||||||
|
- Generated 12 UIDs for new files
|
||||||
|
- U1 complete: `inventory/ItemDefinition.gd` written (Resource with id, name, combination_category)
|
||||||
|
- U2 complete: `inventory/InventoryManager.gd` written (AutoLoad singleton with signals, queries, mutations, combination emission, selection)
|
||||||
|
- U3 complete: `inventory/inventory_backpack/InventoryBackpack.gd` + `.tscn` (FSM with IDLE/OPEN/SELECTED/ACQUIRE/REMOVE, Tween animations, guard checks)
|
||||||
|
- U4 complete: `inventory/inventory_overlay/InventoryOverlay.gd` + `.tscn` + `InventorySlot.gd` + `.tscn` (full-screen overlay, grid, drag-and-drop, hover, combination)
|
||||||
|
- U5 complete: Modified `ActionState.gd` (ITEM=4), `MainGame.gd` (5-action cycling), `Scene.gd` (overlay guard, ITEM input), `GameScript.gd` (GiveItem step)
|
||||||
|
- U6 complete: Modified `Scene.gd` (give_item/remove_item/strip_items helpers), `SetPiece_.gd` (ITEM action handling)
|
||||||
|
- InventoryManager registered as AutoLoad in `project.godot`
|
||||||
|
- All commits pushed to remote
|
||||||
|
|
||||||
|
### In Progress
|
||||||
|
- (none)
|
||||||
|
|
||||||
|
### Blocked
|
||||||
|
- (none)
|
||||||
|
|
||||||
|
## Key Decisions
|
||||||
|
- **Signal-based interactions**: Items emit signals; `InventoryManager.attempt_combine` emits `combination_attempted`; scene scripts handle results
|
||||||
|
- **No transition queues**: FSM transitions kill in-flight tweens and start fresh; `is_busy` flag prevents concurrency but does not queue
|
||||||
|
- **ActionState ITEM slot**: `ITEM = 4` added to enum; right-click cycles all 5 states; selected item stored in `InventoryManager.selected_item`
|
||||||
|
- **Colored boxes**: `ColorRect` placeholders replace all `Sprite2D` references
|
||||||
|
- **Hand-rolled FSM (PRD Option A)** over AnimationTree: conditional branching maps better to code
|
||||||
|
- **AutoLoad singleton** for InventoryManager following ActionState pattern
|
||||||
|
- **Raw `_gui_input()`** for overlay drag-and-drop instead of Godot's built-in system
|
||||||
|
- **Combined input priority defense**: `MOUSE_FILTER_STOP` background + `_unhandled_input()` gate + explicit `overlay_active` guard flag
|
||||||
|
- **ItemDefinition as Resource** for serializable `.tres` item data
|
||||||
|
- **GridContainer** for static item grid layout
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
- Test all units in Godot editor
|
||||||
|
- Register sample item definitions (`.tres` files)
|
||||||
|
- Wire up signal connections in `Game.tscn` (backpack ↔ overlay ↔ manager)
|
||||||
|
- Create example room script demonstrating `give_item()` usage
|
||||||
|
- Replace colored box placeholders with actual item sprites
|
||||||
|
|
||||||
|
## Critical Context
|
||||||
|
- Godot 4.6 project, 1920x1080 viewport
|
||||||
|
- Branch: `sugary-panda` (worktree), default branch: `master`
|
||||||
|
- Existing autoloads: `ActionState`, `CameraTransition`, `InventoryManager` (new)
|
||||||
|
- Root scene `Game.tscn` uses `SubViewport` for game world, `CanvasLayer` for overlays
|
||||||
|
- `ActionState.gd` enum: `WALK=0, LOOK=1, TOUCH=2, TALK=3, ITEM=4`
|
||||||
|
- `MainGame.gd` has `cursors` array with 4 cursor textures — 5th slot needed for ITEM (currently skips if no item selected)
|
||||||
|
- All code committed and pushed to `origin/sugary-panda`
|
||||||
|
|
||||||
|
## Relevant Files
|
||||||
|
- `inventory-prd.md`: Origin requirements document (791 lines, 14 acceptance criteria)
|
||||||
|
- `docs/plans/2026-04-26-001-feat-inventory-backpack-system-plan.md`: Implementation plan (6 units, edited with 5 user changes)
|
||||||
|
- `inventory/ItemDefinition.gd`: Custom Resource class (DONE)
|
||||||
|
- `inventory/ItemDefinition.gd.uid`: UID file for ItemDefinition (DONE)
|
||||||
|
- `inventory/InventoryManager.gd`: AutoLoad singleton with signals, queries, mutations (DONE)
|
||||||
|
- `inventory/InventoryManager.gd.uid`: UID file for InventoryManager (DONE)
|
||||||
|
- `inventory/inventory_backpack/InventoryBackpack.gd`: FSM script (DONE)
|
||||||
|
- `inventory/inventory_backpack/InventoryBackpack.gd.uid`: UID file (DONE)
|
||||||
|
- `inventory/inventory_backpack/InventoryBackpack.tscn`: HUD backpack scene (DONE)
|
||||||
|
- `inventory/inventory_backpack/InventoryBackpack.tscn.uid`: UID file (DONE)
|
||||||
|
- `inventory/inventory_overlay/InventoryOverlay.gd`: Overlay interaction script (DONE)
|
||||||
|
- `inventory/inventory_overlay/InventoryOverlay.gd.uid`: UID file (DONE)
|
||||||
|
- `inventory/inventory_overlay/InventoryOverlay.tscn`: Full-screen overlay scene (DONE)
|
||||||
|
- `inventory/inventory_overlay/InventoryOverlay.tscn.uid`: UID file (DONE)
|
||||||
|
- `inventory/inventory_overlay/InventorySlot.gd`: Slot behavior script (DONE)
|
||||||
|
- `inventory/inventory_overlay/InventorySlot.gd.uid`: UID file (DONE)
|
||||||
|
- `inventory/inventory_overlay/InventorySlot.tscn`: Single item slot scene (DONE)
|
||||||
|
- `inventory/inventory_overlay/InventorySlot.tscn.uid`: UID file (DONE)
|
||||||
|
- `MainGame.gd`: Modified for 5-action cursor cycling with ITEM
|
||||||
|
- `Scene.gd`: Modified for overlay guard, ITEM action, helper methods
|
||||||
|
- `ActionState.gd`: Modified to add ITEM action
|
||||||
|
- `GameScript.gd`: Modified to add GiveItem/GiveItemDeferred steps
|
||||||
|
- `SetPiece_.gd`: Modified to handle ITEM action
|
||||||
|
- `project.godot`: InventoryManager AutoLoad registered
|
||||||
22
Game.tscn
22
Game.tscn
@@ -10,6 +10,8 @@
|
|||||||
[ext_resource type="PackedScene" uid="uid://c0mp4a2u3jkd" path="res://portrait.tscn" id="7_fj12q"]
|
[ext_resource type="PackedScene" uid="uid://c0mp4a2u3jkd" path="res://portrait.tscn" id="7_fj12q"]
|
||||||
[ext_resource type="Script" uid="uid://bsvab128vy1ip" path="res://OffsetCameraBasedOnMovement.gd" id="8_cvftx"]
|
[ext_resource type="Script" uid="uid://bsvab128vy1ip" path="res://OffsetCameraBasedOnMovement.gd" id="8_cvftx"]
|
||||||
[ext_resource type="PackedScene" uid="uid://dyk4rcqsk3aed" path="res://scenes/kq4_003_fountain_pool/kq4_003_fountain_pool.tscn" id="8_yx171"]
|
[ext_resource type="PackedScene" uid="uid://dyk4rcqsk3aed" path="res://scenes/kq4_003_fountain_pool/kq4_003_fountain_pool.tscn" id="8_yx171"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://dxkyfas46q7ef" path="res://inventory/inventory_backpack/InventoryBackpack.tscn" id="9_backpack"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://djoycn4xfa8p3" path="res://inventory/inventory_overlay/InventoryOverlay.tscn" id="a_overlay"]
|
||||||
|
|
||||||
[sub_resource type="ShaderMaterial" id="ShaderMaterial_44mjr"]
|
[sub_resource type="ShaderMaterial" id="ShaderMaterial_44mjr"]
|
||||||
shader = ExtResource("2_jr51a")
|
shader = ExtResource("2_jr51a")
|
||||||
@@ -183,3 +185,23 @@ label_settings = SubResource("LabelSettings_narrator")
|
|||||||
horizontal_alignment = 1
|
horizontal_alignment = 1
|
||||||
vertical_alignment = 1
|
vertical_alignment = 1
|
||||||
autowrap_mode = 3
|
autowrap_mode = 3
|
||||||
|
|
||||||
|
[node name="HUD" type="CanvasLayer" parent="." unique_id=-294967295]
|
||||||
|
layer = 5
|
||||||
|
|
||||||
|
[node name="InventoryBackpack" parent="HUD" unique_id=-294967294 instance=ExtResource("9_backpack")]
|
||||||
|
anchors_preset = 0
|
||||||
|
anchor_top = 0.0
|
||||||
|
anchor_bottom = 0.0
|
||||||
|
offset_top = 0.0
|
||||||
|
offset_bottom = 70.0
|
||||||
|
grow_vertical = 1
|
||||||
|
|
||||||
|
[node name="InventoryOverlayLayer" type="CanvasLayer" parent="." unique_id=-294967293]
|
||||||
|
layer = 10
|
||||||
|
|
||||||
|
[node name="InventoryOverlay" parent="InventoryOverlayLayer" unique_id=-294967292 instance=ExtResource("a_overlay")]
|
||||||
|
|
||||||
|
[connection signal="overlay_hide_requested" from="HUD/InventoryBackpack" to="." method="_on_backpack_hide_overlay"]
|
||||||
|
[connection signal="overlay_show_requested" from="HUD/InventoryBackpack" to="." method="_on_backpack_show_overlay"]
|
||||||
|
[connection signal="item_confirmed" from="InventoryOverlayLayer/InventoryOverlay" to="." method="_on_overlay_item_confirmed"]
|
||||||
|
|||||||
31
MainGame.gd
31
MainGame.gd
@@ -3,6 +3,7 @@ extends Node2D
|
|||||||
|
|
||||||
var cursors = [load("res://boot_icon.png"), load("res://eye_icon.png"), load("res://hand_icon.png"), load("res://speech_icon.png")]
|
var cursors = [load("res://boot_icon.png"), load("res://eye_icon.png"), load("res://hand_icon.png"), load("res://speech_icon.png")]
|
||||||
var hourglass_cursor = load("res://hourglass_icon.png")
|
var hourglass_cursor = load("res://hourglass_icon.png")
|
||||||
|
var item_cursor: Texture2D = null
|
||||||
var previous_cursor_index: int = 0
|
var previous_cursor_index: int = 0
|
||||||
var is_script_running: bool = false
|
var is_script_running: bool = false
|
||||||
var is_cursor_locked: bool = false # When true, hourglass is shown and cursor can't be changed
|
var is_cursor_locked: bool = false # When true, hourglass is shown and cursor can't be changed
|
||||||
@@ -69,11 +70,33 @@ func set_script_cursor() -> void:
|
|||||||
func restore_cursor() -> void:
|
func restore_cursor() -> void:
|
||||||
is_script_running = false
|
is_script_running = false
|
||||||
is_cursor_locked = false # Unlock cursor
|
is_cursor_locked = false # Unlock cursor
|
||||||
Input.set_custom_mouse_cursor(cursors[previous_cursor_index])
|
if previous_cursor_index == ActionState.Action.ITEM:
|
||||||
|
if item_cursor:
|
||||||
|
Input.set_custom_mouse_cursor(item_cursor)
|
||||||
|
else:
|
||||||
|
Input.set_custom_mouse_cursor(cursors[ActionState.Action.WALK])
|
||||||
|
else:
|
||||||
|
Input.set_custom_mouse_cursor(cursors[previous_cursor_index])
|
||||||
|
|
||||||
func _unhandled_input(event: InputEvent) -> void:
|
func _unhandled_input(event: InputEvent) -> void:
|
||||||
$SceneViewport.push_input(event)
|
$SceneViewport.push_input(event)
|
||||||
|
|
||||||
|
func _on_backpack_show_overlay() -> void:
|
||||||
|
$InventoryOverlayLayer/InventoryOverlay.show_overlay()
|
||||||
|
|
||||||
|
func _on_backpack_hide_overlay() -> void:
|
||||||
|
$InventoryOverlayLayer/InventoryOverlay.hide_overlay()
|
||||||
|
|
||||||
|
func _on_overlay_item_confirmed(item_id: String) -> void:
|
||||||
|
InventoryManager.select_item(item_id)
|
||||||
|
var def = InventoryManager.get_item_definition(item_id)
|
||||||
|
if def and def.icon:
|
||||||
|
item_cursor = def.icon
|
||||||
|
Input.set_custom_mouse_cursor(item_cursor)
|
||||||
|
ActionState.current_action = ActionState.Action.ITEM
|
||||||
|
else:
|
||||||
|
Input.set_custom_mouse_cursor(cursors[ActionState.Action.WALK])
|
||||||
|
|
||||||
func _input(event):
|
func _input(event):
|
||||||
if event.is_action_released("quit"):
|
if event.is_action_released("quit"):
|
||||||
get_tree().quit()
|
get_tree().quit()
|
||||||
@@ -81,8 +104,8 @@ func _input(event):
|
|||||||
var prev_action = ActionState.current_action
|
var prev_action = ActionState.current_action
|
||||||
ActionState.current_action = (ActionState.current_action + 1) % 5
|
ActionState.current_action = (ActionState.current_action + 1) % 5
|
||||||
if ActionState.current_action == ActionState.Action.ITEM:
|
if ActionState.current_action == ActionState.Action.ITEM:
|
||||||
if InventoryManager.selected_item:
|
if InventoryManager.selected_item and item_cursor:
|
||||||
Input.set_custom_mouse_cursor(cursors[ActionState.current_action], Input.CursorShape.CURSOR_ARROW, Vector2(0,0))
|
Input.set_custom_mouse_cursor(item_cursor, Input.CursorShape.CURSOR_ARROW, Vector2(0,0))
|
||||||
else:
|
else:
|
||||||
ActionState.current_action = (ActionState.current_action + 1) % 5
|
ActionState.current_action = (ActionState.current_action + 1) % 5
|
||||||
Input.set_custom_mouse_cursor(cursors[ActionState.current_action], Input.CursorShape.CURSOR_ARROW, Vector2(0,0))
|
Input.set_custom_mouse_cursor(cursors[ActionState.current_action], Input.CursorShape.CURSOR_ARROW, Vector2(0,0))
|
||||||
|
|||||||
1
godot-mcp
Submodule
1
godot-mcp
Submodule
Submodule godot-mcp added at b77dfc7c62
@@ -3,4 +3,5 @@ class_name ItemDefinition
|
|||||||
|
|
||||||
@export var id: String = ""
|
@export var id: String = ""
|
||||||
@export var name: String = ""
|
@export var name: String = ""
|
||||||
|
@export var icon: Texture2D
|
||||||
@export var combination_category: String = ""
|
@export var combination_category: String = ""
|
||||||
|
|||||||
@@ -13,12 +13,14 @@ var _state: State = State.IDLE
|
|||||||
var _animating: bool = false
|
var _animating: bool = false
|
||||||
var _active_tween: Tween = null
|
var _active_tween: Tween = null
|
||||||
var _floating_item_color: Color = Color(1, 1, 1, 0)
|
var _floating_item_color: Color = Color(1, 1, 1, 0)
|
||||||
|
var _home_position: Vector2 = Vector2(0, 0)
|
||||||
|
|
||||||
@onready var backpack_icon: ColorRect = $BackpackIcon
|
@onready var backpack_icon: ColorRect = $BackpackIcon
|
||||||
@onready var floating_item: ColorRect = $FloatingItem
|
@onready var floating_item: ColorRect = $FloatingItem
|
||||||
@onready var animation_player: AnimationPlayer = $AnimationPlayer
|
@onready var animation_player: AnimationPlayer = $AnimationPlayer
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
|
_home_position = backpack_icon.position
|
||||||
floating_item.modulate = Color(1, 1, 1, 0)
|
floating_item.modulate = Color(1, 1, 1, 0)
|
||||||
floating_item.visible = false
|
floating_item.visible = false
|
||||||
InventoryManager.item_acquired.connect(_on_item_acquired)
|
InventoryManager.item_acquired.connect(_on_item_acquired)
|
||||||
@@ -71,8 +73,8 @@ func _transition_to_idle() -> void:
|
|||||||
_active_tween = tween
|
_active_tween = tween
|
||||||
_animating = true
|
_animating = true
|
||||||
tween.tween_property(backpack_icon, "rotation", 0.0, 0.35).set_trans(Tween.TRANS_LINEAR)
|
tween.tween_property(backpack_icon, "rotation", 0.0, 0.35).set_trans(Tween.TRANS_LINEAR)
|
||||||
tween.tween_property(backpack_icon, "position", backpack_icon.position, 0.35).set_trans(Tween.TRANS_SINE_IN)
|
tween.tween_property(backpack_icon, "position", _home_position, 0.35).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN)
|
||||||
tween.tween_callback(_on_transition_complete).bind(State.IDLE)
|
tween.tween_callback(_on_transition_complete.bind(State.IDLE))
|
||||||
|
|
||||||
func _transition_to_open() -> void:
|
func _transition_to_open() -> void:
|
||||||
var can_open = _check_guards()
|
var can_open = _check_guards()
|
||||||
@@ -87,8 +89,8 @@ func _transition_to_open() -> void:
|
|||||||
_active_tween = tween
|
_active_tween = tween
|
||||||
_animating = true
|
_animating = true
|
||||||
tween.tween_property(backpack_icon, "rotation", PI / 4, 0.35).set_trans(Tween.TRANS_LINEAR)
|
tween.tween_property(backpack_icon, "rotation", PI / 4, 0.35).set_trans(Tween.TRANS_LINEAR)
|
||||||
tween.tween_property(backpack_icon, "position", Vector2(backpack_icon.position.x + 20, backpack_icon.position.y + 20), 0.35).set_trans(Tween.TRANS_SINE_IN)
|
tween.tween_property(backpack_icon, "position", _home_position + Vector2(20, 20), 0.35).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN)
|
||||||
tween.tween_callback(_on_transition_complete).bind(State.OPEN)
|
tween.tween_callback(_on_transition_complete.bind(State.OPEN))
|
||||||
tween.tween_callback(overlay_show_requested.emit)
|
tween.tween_callback(overlay_show_requested.emit)
|
||||||
|
|
||||||
func _transition_to_selected() -> void:
|
func _transition_to_selected() -> void:
|
||||||
@@ -105,7 +107,7 @@ func _transition_to_selected() -> void:
|
|||||||
floating_item.visible = true
|
floating_item.visible = true
|
||||||
floating_item.modulate = Color(1, 1, 1, 0)
|
floating_item.modulate = Color(1, 1, 1, 0)
|
||||||
tween.tween_property(floating_item, "modulate", Color(1, 1, 1, 1), 0.5).set_trans(Tween.TRANS_LINEAR)
|
tween.tween_property(floating_item, "modulate", Color(1, 1, 1, 1), 0.5).set_trans(Tween.TRANS_LINEAR)
|
||||||
tween.tween_callback(_on_transition_complete).bind(State.SELECTED)
|
tween.tween_callback(_on_transition_complete.bind(State.SELECTED))
|
||||||
|
|
||||||
func _transition_to_acquire() -> void:
|
func _transition_to_acquire() -> void:
|
||||||
if _state == State.ACQUIRE or _state == State.REMOVE:
|
if _state == State.ACQUIRE or _state == State.REMOVE:
|
||||||
@@ -222,10 +224,13 @@ func _on_inventory_changed() -> void:
|
|||||||
_update_floating_item()
|
_update_floating_item()
|
||||||
|
|
||||||
func _gui_input(event: InputEvent) -> void:
|
func _gui_input(event: InputEvent) -> void:
|
||||||
|
print("[BACKPACK] _gui_input: %s, state=%s" % [event, State.keys()[_state]])
|
||||||
if event is InputEventMouseButton and event.pressed and event.button_index == 1:
|
if event is InputEventMouseButton and event.pressed and event.button_index == 1:
|
||||||
if _state == State.IDLE:
|
if _state == State.IDLE:
|
||||||
|
print("[BACKPACK] transitioning to OPEN")
|
||||||
transition_to(State.OPEN)
|
transition_to(State.OPEN)
|
||||||
elif _state == State.OPEN:
|
elif _state == State.OPEN:
|
||||||
|
print("[BACKPACK] transitioning to IDLE")
|
||||||
transition_to(State.IDLE)
|
transition_to(State.IDLE)
|
||||||
|
|
||||||
func _notification(what: int) -> void:
|
func _notification(what: int) -> void:
|
||||||
|
|||||||
@@ -1,31 +1,30 @@
|
|||||||
[gd_scene format=3 uid="uid://1406xmcnkygw0"]
|
[gd_scene format=3 uid="uid://dxkyfas46q7ef"]
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://2x3g0ethsdcgo" path="res://inventory/inventory_backpack/InventoryBackpack.gd" id="1"]
|
[ext_resource type="Script" uid="uid://v8du0eptw65c" path="res://inventory/inventory_backpack/InventoryBackpack.gd" id="1"]
|
||||||
|
|
||||||
[node name="InventoryBackpack" type="Control" unique_id=1000000001]
|
[node name="InventoryBackpack" type="Control" unique_id=1000000001]
|
||||||
layout_mode = 3
|
layout_mode = 3
|
||||||
anchors_preset = 2
|
anchors_preset = 2
|
||||||
anchor_right = 1.0
|
anchor_top = 1.0
|
||||||
offset_top = 10.0
|
anchor_bottom = 1.0
|
||||||
offset_right = -10.0
|
offset_top = -70.0
|
||||||
offset_bottom = 70.0
|
offset_right = 70.0
|
||||||
|
grow_vertical = 0
|
||||||
script = ExtResource("1")
|
script = ExtResource("1")
|
||||||
|
|
||||||
[node name="BackpackIcon" type="ColorRect" parent="." unique_id=1000000002]
|
[node name="BackpackIcon" type="ColorRect" parent="." unique_id=1000000002]
|
||||||
layout_mode = 0
|
layout_mode = 0
|
||||||
offset_left = 0.0
|
|
||||||
offset_top = 0.0
|
|
||||||
offset_right = 60.0
|
offset_right = 60.0
|
||||||
offset_bottom = 60.0
|
offset_bottom = 60.0
|
||||||
|
mouse_filter = 1
|
||||||
color = Color(0.4, 0.6, 0.9, 1)
|
color = Color(0.4, 0.6, 0.9, 1)
|
||||||
|
|
||||||
[node name="FloatingItem" type="ColorRect" parent="." unique_id=1000000003]
|
[node name="FloatingItem" type="ColorRect" parent="." unique_id=1000000003]
|
||||||
|
visible = false
|
||||||
layout_mode = 0
|
layout_mode = 0
|
||||||
offset_left = 20.0
|
offset_left = 20.0
|
||||||
offset_top = -30.0
|
offset_top = -30.0
|
||||||
offset_right = 50.0
|
offset_right = 50.0
|
||||||
offset_bottom = 0.0
|
|
||||||
color = Color(1, 0.6, 0.2, 1)
|
color = Color(1, 0.6, 0.2, 1)
|
||||||
visible = false
|
|
||||||
|
|
||||||
[node name="AnimationPlayer" type="AnimationPlayer" parent="." unique_id=1000000004]
|
[node name="AnimationPlayer" type="AnimationPlayer" parent="." unique_id=1000000004]
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ func _ready() -> void:
|
|||||||
InventoryManager.combination_attempted.connect(_on_combination_attempted)
|
InventoryManager.combination_attempted.connect(_on_combination_attempted)
|
||||||
|
|
||||||
func show_overlay() -> void:
|
func show_overlay() -> void:
|
||||||
|
print("[OVERLAY] show_overlay called, inventory has %d items" % InventoryManager.inventory.size())
|
||||||
|
_refresh_grid()
|
||||||
if _fade_tween:
|
if _fade_tween:
|
||||||
_fade_tween.kill()
|
_fade_tween.kill()
|
||||||
_fade_tween = null
|
_fade_tween = null
|
||||||
@@ -48,6 +50,7 @@ func show_overlay() -> void:
|
|||||||
tween.tween_callback(_on_fade_in_complete)
|
tween.tween_callback(_on_fade_in_complete)
|
||||||
|
|
||||||
func hide_overlay() -> void:
|
func hide_overlay() -> void:
|
||||||
|
print("[OVERLAY] hide_overlay called")
|
||||||
if _fade_tween:
|
if _fade_tween:
|
||||||
_fade_tween.kill()
|
_fade_tween.kill()
|
||||||
_fade_tween = null
|
_fade_tween = null
|
||||||
@@ -84,28 +87,30 @@ func _refresh_grid() -> void:
|
|||||||
|
|
||||||
var slot_scene = load("res://inventory/inventory_overlay/InventorySlot.tscn")
|
var slot_scene = load("res://inventory/inventory_overlay/InventorySlot.tscn")
|
||||||
var slot: InventorySlot = slot_scene.instantiate()
|
var slot: InventorySlot = slot_scene.instantiate()
|
||||||
|
grid.add_child(slot)
|
||||||
slot.set_item(def)
|
slot.set_item(def)
|
||||||
slot.clicked.connect(_on_slot_clicked)
|
slot.clicked.connect(_on_slot_clicked)
|
||||||
slot.right_clicked.connect(_on_slot_right_clicked)
|
slot.right_clicked.connect(_on_slot_right_clicked)
|
||||||
slot.hovered.connect(_on_slot_hovered)
|
slot.hovered.connect(_on_slot_hovered)
|
||||||
slot.unhovered.connect(_on_slot_unhovered)
|
slot.unhovered.connect(_on_slot_unhovered)
|
||||||
grid.add_child(slot)
|
|
||||||
|
|
||||||
grid.columns = SLOTS_PER_ROW
|
grid.columns = SLOTS_PER_ROW
|
||||||
|
|
||||||
func _on_slot_clicked(item_id: String) -> void:
|
func _on_slot_clicked(item_id: String) -> void:
|
||||||
|
print("[OVERLAY] _on_slot_clicked: '%s', input_active=%s" % [item_id, input_active])
|
||||||
if not input_active:
|
if not input_active:
|
||||||
return
|
return
|
||||||
|
|
||||||
for child in grid.get_children():
|
for child in grid.get_children():
|
||||||
if child is InventorySlot and child.item_id == item_id:
|
if child is InventorySlot and child.item_id == item_id:
|
||||||
if _selected_slot == null:
|
if _selected_slot == null:
|
||||||
_selected_slot = child
|
InventoryManager.select_item(item_id)
|
||||||
_drag_start_time = Time.get_ticks_msec() / 1000.0
|
item_confirmed.emit(item_id)
|
||||||
_is_dragging = true
|
hide_overlay()
|
||||||
_create_drag_preview(child)
|
|
||||||
elif _selected_slot.item_id == item_id:
|
elif _selected_slot.item_id == item_id:
|
||||||
_handle_release_same_item()
|
InventoryManager.select_item(item_id)
|
||||||
|
item_confirmed.emit(item_id)
|
||||||
|
hide_overlay()
|
||||||
else:
|
else:
|
||||||
combine_requested.emit(_selected_slot.item_id, item_id)
|
combine_requested.emit(_selected_slot.item_id, item_id)
|
||||||
_clear_selection()
|
_clear_selection()
|
||||||
@@ -176,35 +181,19 @@ func _update_hover_label() -> void:
|
|||||||
else:
|
else:
|
||||||
hover_label.text = ""
|
hover_label.text = ""
|
||||||
|
|
||||||
|
func _on_background_gui_input(event: InputEvent) -> void:
|
||||||
|
if event is InputEventMouseButton and event.button_index == 1 and event.pressed:
|
||||||
|
hide_overlay()
|
||||||
|
close_requested.emit()
|
||||||
|
|
||||||
func _gui_input(event: InputEvent) -> void:
|
func _gui_input(event: InputEvent) -> void:
|
||||||
if not _is_visible:
|
if event is InputEventMouseButton and event.button_index == 1 and event.pressed:
|
||||||
return
|
|
||||||
|
|
||||||
if event is InputEventMouseButton:
|
|
||||||
if event.button_index == 1 and event.pressed:
|
|
||||||
if not _is_dragging:
|
|
||||||
pass
|
|
||||||
elif event.button_index == 1 and not event.pressed:
|
|
||||||
if _is_dragging:
|
|
||||||
if _hovered_slot == null:
|
|
||||||
_clear_selection()
|
|
||||||
hide_overlay()
|
|
||||||
close_requested.emit()
|
|
||||||
elif _hovered_slot == _selected_slot:
|
|
||||||
_handle_release_same_item()
|
|
||||||
else:
|
|
||||||
combine_requested.emit(_selected_slot.item_id, _hovered_slot.item_id)
|
|
||||||
_clear_selection()
|
|
||||||
return
|
|
||||||
|
|
||||||
if event is InputEventMouseMotion and _is_dragging and _dragged_item:
|
|
||||||
_dragged_item.position = get_local_mouse_position() - Vector2(24, 24)
|
|
||||||
var panel_rect = panel.get_global_rect()
|
var panel_rect = panel.get_global_rect()
|
||||||
if not panel_rect.has_point(get_global_mouse_position()):
|
if not panel_rect.has_point(get_global_mouse_position()):
|
||||||
_clear_selection()
|
|
||||||
hide_overlay()
|
hide_overlay()
|
||||||
close_requested.emit()
|
close_requested.emit()
|
||||||
|
|
||||||
|
|
||||||
func _on_combination_attempted(item_a_id: String, item_b_id: String) -> void:
|
func _on_combination_attempted(item_a_id: String, item_b_id: String) -> void:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
@@ -1,29 +1,34 @@
|
|||||||
[gd_scene format=3 uid="uid://1p46uzngsih9o"]
|
[gd_scene format=3 uid="uid://djoycn4xfa8p3"]
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://3mkdj9s1oe1jz" path="res://inventory/inventory_overlay/InventoryOverlay.gd" id="1"]
|
[ext_resource type="Script" uid="uid://bkpafveapyv8n" path="res://inventory/inventory_overlay/InventoryOverlay.gd" id="1"]
|
||||||
|
|
||||||
[sub_resource type="LabelSettings" id="LabelSettings_inv"]
|
[sub_resource type="LabelSettings" id="LabelSettings_inv"]
|
||||||
font_size = 20
|
font_size = 20
|
||||||
outline_size = 3
|
outline_size = 3
|
||||||
outline_color = Color(0, 0, 0, 1)
|
outline_color = Color(0, 0, 0, 1)
|
||||||
|
|
||||||
[node name="InventoryOverlay" type="Control" unique_id=3000000001]
|
[node name="InventoryOverlay" type="Control" unique_id=-1294967295]
|
||||||
layout_mode = 3
|
layout_mode = 3
|
||||||
anchors_preset = 15
|
anchors_preset = 15
|
||||||
anchor_right = 1.0
|
anchor_right = 1.0
|
||||||
anchor_bottom = 1.0
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
script = ExtResource("1")
|
script = ExtResource("1")
|
||||||
|
|
||||||
[node name="Background" type="ColorRect" parent="." unique_id=3000000002]
|
[node name="Background" type="ColorRect" parent="." unique_id=-1294967294]
|
||||||
layout_mode = 1
|
layout_mode = 1
|
||||||
anchors_preset = 15
|
anchors_preset = 15
|
||||||
anchor_right = 1.0
|
anchor_right = 1.0
|
||||||
anchor_bottom = 1.0
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
mouse_filter = 1
|
||||||
color = Color(0, 0, 0, 0.7)
|
color = Color(0, 0, 0, 0.7)
|
||||||
|
|
||||||
[node name="InventoryPanel" type="Control" parent="." unique_id=3000000003]
|
[node name="InventoryPanel" type="Control" parent="." unique_id=-1294967293]
|
||||||
layout_mode = 1
|
layout_mode = 1
|
||||||
anchors_preset = 7
|
anchors_preset = 8
|
||||||
anchor_left = 0.5
|
anchor_left = 0.5
|
||||||
anchor_top = 0.5
|
anchor_top = 0.5
|
||||||
anchor_right = 0.5
|
anchor_right = 0.5
|
||||||
@@ -35,29 +40,38 @@ offset_bottom = 150.0
|
|||||||
grow_horizontal = 2
|
grow_horizontal = 2
|
||||||
grow_vertical = 2
|
grow_vertical = 2
|
||||||
|
|
||||||
[node name="Frame" type="ColorRect" parent="InventoryPanel" unique_id=3000000004]
|
[node name="Frame" type="ColorRect" parent="InventoryPanel" unique_id=-1294967292]
|
||||||
layout_mode = 1
|
layout_mode = 1
|
||||||
anchors_preset = 15
|
anchors_preset = 15
|
||||||
anchor_right = 1.0
|
anchor_right = 1.0
|
||||||
anchor_bottom = 1.0
|
anchor_bottom = 1.0
|
||||||
|
mouse_filter = 1
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
color = Color(0.15, 0.15, 0.2, 1)
|
color = Color(0.15, 0.15, 0.2, 1)
|
||||||
|
|
||||||
[node name="ItemGrid" type="GridContainer" parent="InventoryPanel" unique_id=3000000005]
|
[node name="ItemGrid" type="GridContainer" parent="InventoryPanel" unique_id=-1294967291]
|
||||||
layout_mode = 1
|
layout_mode = 1
|
||||||
anchors_preset = 0
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
offset_left = 10.0
|
offset_left = 10.0
|
||||||
offset_top = 10.0
|
offset_top = 10.0
|
||||||
offset_right = -10.0
|
offset_right = -10.0
|
||||||
offset_bottom = -50.0
|
offset_bottom = -50.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
|
||||||
[node name="HoverLabel" type="Label" parent="InventoryPanel" unique_id=3000000006]
|
[node name="HoverLabel" type="Label" parent="InventoryPanel" unique_id=-1294967290]
|
||||||
layout_mode = 1
|
layout_mode = 1
|
||||||
anchors_preset = 8
|
anchors_preset = 12
|
||||||
anchor_left = 0.0
|
|
||||||
anchor_top = 1.0
|
anchor_top = 1.0
|
||||||
anchor_right = 1.0
|
anchor_right = 1.0
|
||||||
anchor_bottom = 1.0
|
anchor_bottom = 1.0
|
||||||
offset_bottom = -10.0
|
offset_bottom = -10.0
|
||||||
grow_horizontal = 2
|
grow_horizontal = 2
|
||||||
horizontal_alignment = 1
|
grow_vertical = 2
|
||||||
label_settings = SubResource("LabelSettings_inv")
|
label_settings = SubResource("LabelSettings_inv")
|
||||||
|
horizontal_alignment = 1
|
||||||
|
|
||||||
|
[connection signal="gui_input" from="Background" to="." method="_on_background_gui_input"]
|
||||||
|
|||||||
@@ -35,8 +35,10 @@ func set_hover(hovered: bool) -> void:
|
|||||||
item_box.color = Color(0.8, 0.8, 0.8, 1)
|
item_box.color = Color(0.8, 0.8, 0.8, 1)
|
||||||
|
|
||||||
func _gui_input(event: InputEvent) -> void:
|
func _gui_input(event: InputEvent) -> void:
|
||||||
|
print("[SLOT:%s] _gui_input: %s" % [item_id, event])
|
||||||
if event is InputEventMouseButton:
|
if event is InputEventMouseButton:
|
||||||
if event.button_index == 1 and event.pressed:
|
if event.button_index == 1 and event.pressed:
|
||||||
|
print("[SLOT:%s] emitting clicked" % item_id)
|
||||||
clicked.emit(item_id)
|
clicked.emit(item_id)
|
||||||
elif event.button_index == 2:
|
elif event.button_index == 2:
|
||||||
right_clicked.emit(item_id)
|
right_clicked.emit(item_id)
|
||||||
|
|||||||
@@ -1,26 +1,32 @@
|
|||||||
[gd_scene format=3 uid="uid://1esl88fgtd2p6"]
|
[gd_scene format=3 uid="uid://c7depvvxf5s6l"]
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://oegm753jbl9m" path="res://inventory/inventory_overlay/InventorySlot.gd" id="1"]
|
[ext_resource type="Script" uid="uid://oegm753jbmam" path="res://inventory/inventory_overlay/InventorySlot.gd" id="1"]
|
||||||
|
|
||||||
[node name="InventorySlot" type="Control" unique_id=2000000001]
|
[node name="InventorySlot" type="Control" unique_id=2000000001]
|
||||||
custom_minimum_size = Vector2i(64, 64)
|
custom_minimum_size = Vector2(64, 64)
|
||||||
|
layout_mode = 3
|
||||||
|
anchors_preset = 0
|
||||||
script = ExtResource("1")
|
script = ExtResource("1")
|
||||||
|
|
||||||
[node name="ItemBox" type="ColorRect" parent="." unique_id=2000000002]
|
[node name="ItemBox" type="ColorRect" parent="." unique_id=2000000002]
|
||||||
layout_mode = 1
|
layout_mode = 1
|
||||||
anchors_preset = 8
|
anchors_preset = -1
|
||||||
anchor_left = 0.062
|
anchor_left = 0.062
|
||||||
anchor_top = 0.062
|
anchor_top = 0.062
|
||||||
anchor_right = 0.938
|
anchor_right = 0.938
|
||||||
anchor_bottom = 0.938
|
anchor_bottom = 0.938
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
mouse_filter = 1
|
||||||
color = Color(1, 0.6, 0.2, 1)
|
color = Color(1, 0.6, 0.2, 1)
|
||||||
|
|
||||||
[node name="HoverHighlight" type="ColorRect" parent="." unique_id=2000000003]
|
[node name="HoverHighlight" type="ColorRect" parent="." unique_id=2000000003]
|
||||||
|
visible = false
|
||||||
layout_mode = 1
|
layout_mode = 1
|
||||||
anchors_preset = 8
|
anchors_preset = 15
|
||||||
anchor_left = 0.0
|
|
||||||
anchor_top = 0.0
|
|
||||||
anchor_right = 1.0
|
anchor_right = 1.0
|
||||||
anchor_bottom = 1.0
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
mouse_filter = 1
|
||||||
color = Color(1, 1, 1, 0.3)
|
color = Color(1, 1, 1, 0.3)
|
||||||
visible = false
|
|
||||||
|
|||||||
6
inventory/items/splash_item.tres
Normal file
6
inventory/items/splash_item.tres
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"item_id": "splash",
|
||||||
|
"name": "Splash",
|
||||||
|
"icon": "res://splash.png",
|
||||||
|
"combination_category": "potion"
|
||||||
|
}
|
||||||
@@ -24,6 +24,7 @@ config/icon="res://icon.png"
|
|||||||
ActionState="*res://ActionState.gd"
|
ActionState="*res://ActionState.gd"
|
||||||
CameraTransition="*res://camera_transition.tscn"
|
CameraTransition="*res://camera_transition.tscn"
|
||||||
InventoryManager="*res://inventory/InventoryManager.gd"
|
InventoryManager="*res://inventory/InventoryManager.gd"
|
||||||
|
McpInteractionServer="*uid://dovjioj1jyqpp"
|
||||||
|
|
||||||
[display]
|
[display]
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,17 @@
|
|||||||
extends Scene
|
extends Scene
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
super._ready()
|
||||||
|
var def = ItemDefinition.new()
|
||||||
|
def.id = "splash"
|
||||||
|
def.name = "Splash"
|
||||||
|
def.icon = load("res://splash.png")
|
||||||
|
def.combination_category = "potion"
|
||||||
|
InventoryManager.register_item(def)
|
||||||
|
give_item("splash")
|
||||||
|
|
||||||
|
|
||||||
func _on_meadow_interacted() -> void:
|
func _on_meadow_interacted() -> void:
|
||||||
$kq4_002_meadow.default_script(self)
|
$kq4_002_meadow.default_script(self)
|
||||||
|
|
||||||
|
|||||||
4421
scripts/mcp_interaction_server.gd
Normal file
4421
scripts/mcp_interaction_server.gd
Normal file
File diff suppressed because it is too large
Load Diff
1
scripts/mcp_interaction_server.gd.uid
Normal file
1
scripts/mcp_interaction_server.gd.uid
Normal file
@@ -0,0 +1 @@
|
|||||||
|
uid://dovjioj1jyqpp
|
||||||
BIN
splash.png
LFS
Normal file
BIN
splash.png
LFS
Normal file
Binary file not shown.
40
splash.png.import
Normal file
40
splash.png.import
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://cxu3klicoldpv"
|
||||||
|
path="res://.godot/imported/splash.png-929ed8a00b89ba36c51789452f874c77.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://splash.png"
|
||||||
|
dest_files=["res://.godot/imported/splash.png-929ed8a00b89ba36c51789452f874c77.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
Reference in New Issue
Block a user