feat: integrate inventory with cursor system, scene input, and GameScript

- ActionState: add ITEM action (value 4) to enum and get_action_name()
- MainGame: right-click cycles through all 5 actions including ITEM;
  skips ITEM if nothing selected; clears selection when cycling away
- Scene: guard _unhandled_input() against active inventory overlay;
  handle ITEM action for world-wide item use; add give_item(),
  remove_item(), strip_items() helper methods
- SetPiece: handle ITEM action by calling scene's _use_item_on_setpiece()
- GameScript: add GiveItem and GiveItemDeferred script step classes
  for item acquisition during cutscenes
This commit is contained in:
2026-04-26 21:10:39 -07:00
parent 975b51a2b5
commit 8661fbad15
5 changed files with 114 additions and 4 deletions

View File

@@ -1,6 +1,6 @@
extends Node
enum Action { WALK = 0, LOOK = 1, TOUCH = 2, TALK = 3 }
enum Action { WALK = 0, LOOK = 1, TOUCH = 2, TALK = 3, ITEM = 4 }
var current_action: int = Action.WALK:
set(value):
@@ -22,6 +22,7 @@ func get_action_name() -> String:
Action.LOOK: return "look"
Action.TOUCH: return "touch"
Action.TALK: return "talk"
Action.ITEM: return "item"
return "walk"
func get_action_enum() -> int:

View File

@@ -476,5 +476,54 @@ func switch_camera(path):
func reset_camera():
var thing = ResetCamera.new()
return thing
class GiveItem:
extends ScriptNode
var item_id: String = ""
var text: String = ""
var subject: Node2D = null
var done = false
var started = false
func step_type():
return "GiveItem " + item_id
func init(scene):
super(scene)
func do(delta):
if not started:
started = true
if text:
await scene.find_child("dialogue").say(text)
InventoryManager.acquire_item(item_id)
done = true
func is_done():
return done
func interrupt():
done = true
class GiveItemDeferred:
extends GiveItem
var subject_name: String = ""
func init(scene):
super(scene)
subject = scene.get_node(subject_name)
func give_item(item_id: String, text: String = ""):
var step = GiveItem.new()
step.item_id = item_id
step.text = text
return step
func give_item_deferred(item_id: String, subject_name: String, text: String = ""):
var step = GiveItemDeferred.new()
step.item_id = item_id
step.subject_name = subject_name
step.text = text
return step
var current_script : ScriptGraph = null

View File

@@ -78,5 +78,15 @@ func _input(event):
if event.is_action_released("quit"):
get_tree().quit()
if event.is_action_released("right_click") and not is_cursor_locked:
ActionState.current_action = (ActionState.current_action + 1) % 4
Input.set_custom_mouse_cursor(cursors[ActionState.current_action], Input.CursorShape.CURSOR_ARROW, Vector2(0,0))
var prev_action = ActionState.current_action
ActionState.current_action = (ActionState.current_action + 1) % 5
if ActionState.current_action == ActionState.Action.ITEM:
if InventoryManager.selected_item:
Input.set_custom_mouse_cursor(cursors[ActionState.current_action], Input.CursorShape.CURSOR_ARROW, Vector2(0,0))
else:
ActionState.current_action = (ActionState.current_action + 1) % 5
Input.set_custom_mouse_cursor(cursors[ActionState.current_action], Input.CursorShape.CURSOR_ARROW, Vector2(0,0))
else:
if prev_action == ActionState.Action.ITEM:
InventoryManager.clear_selection()
Input.set_custom_mouse_cursor(cursors[ActionState.current_action], Input.CursorShape.CURSOR_ARROW, Vector2(0,0))

View File

@@ -128,7 +128,12 @@ func _unhandled_input(event):
if ScriptBuilder.current_script and not ScriptBuilder.current_script.can_interrupt:
if ScriptBuilder.current_script.handle_input(event):
return
# Block input when inventory overlay is active
var overlay = get_node_or_null("/root/Node2D/InventoryOverlay")
if overlay and overlay is InventoryOverlay and overlay.is_active():
return
var root = get_node("/root/Node2D")
# If look cursor is active and we got here, no SetPiece handled the input
# so this is a room-wide look
@@ -138,7 +143,46 @@ func _unhandled_input(event):
if ActionState.current_action == ActionState.Action.WALK:
var path = NavigationServer2D.map_get_path(map, ego.position, pathfind.to_local(get_global_mouse_position()), true)
start_main_script(ScriptBuilder.init(ScriptBuilder.walk_path(ego, path)).can_interrupt().build(self, "_on_script_complete"))
if ActionState.current_action == ActionState.Action.ITEM:
_on_item_use_in_world()
func _on_room_looked() -> void:
# Default room look description - override in room scripts
pass
func _on_item_use_in_world() -> void:
if not InventoryManager.selected_item:
return
var item_id = InventoryManager.selected_item
var top_piece = ActionState.get_top_hovered_setpiece()
if top_piece:
_use_item_on_setpiece(item_id, top_piece)
else:
_on_item_used_empty_space(item_id)
func _use_item_on_setpiece(item_id: String, piece: SetPiece) -> void:
if piece.has_method("_on_item_used"):
piece._on_item_used(item_id)
else:
var def = InventoryManager.get_item_definition(item_id)
var item_name = item_id
if def:
item_name = def.name
var piece_name = piece.label if piece.label else piece.name
start_main_script(ScriptBuilder.init(ScriptBuilder.say(ego, "I can't use the %s on the %s." % [item_name, piece_name])).build(self, "_on_script_complete"))
func _on_item_used_empty_space(item_id: String) -> void:
var def = InventoryManager.get_item_definition(item_id)
var item_name = item_id
if def:
item_name = def.name
start_main_script(ScriptBuilder.init(ScriptBuilder.say(ego, "There's nothing to use the %s on here." % [item_name])).build(self, "_on_script_complete"))
func give_item(item_id: String) -> void:
InventoryManager.acquire_item(item_id)
func remove_item(item_id: String, quiet: bool = false) -> void:
InventoryManager.remove_item(item_id, quiet)
func strip_items(event_items: Array[String], exempt_items: Array[String] = []) -> void:
InventoryManager.bulk_strip_items(event_items, exempt_items)

View File

@@ -75,3 +75,9 @@ func _input(event):
ActionState.Action.TALK:
if talked.get_connections().size() > 0:
emit_signal("talked")
ActionState.Action.ITEM:
if InventoryManager.selected_item:
var item_id = InventoryManager.selected_item
var scene = get_node_or_null("/root/Node2D/SceneViewport/background")
if scene and scene is Scene:
scene._use_item_on_setpiece(item_id, self)