# Copyright (C) 2022-2023 John Pennycook # SPDX-License-Identifier: MIT @tool @icon("res://addons/input_prompts/action_prompt/icon.svg") class_name ActionPrompt extends "res://addons/input_prompts/input_prompt.gd" ## Displays a prompt based on an action registered in the [InputMap]. ## ## Displays a prompt based on an action registered in the [InputMap]. ## The texture used for the prompt is determined automatically, based on the ## contents of the [InputMap] and an icon preference. When the icon preference ## is set to "Automatic", the prompt automatically adjusts to match the most ## recent input device. ## The name of an action registered in the [InputMap]. var action := "ui_accept": set = _set_action ## The icon preference for this prompt: ## Automatic (0), Xbox (1), Sony (2), Nintendo (3), Keyboard (4). ## When set to "Automatic", the prompt automatically adjusts to match the most ## recent input device. var icon: int = Icons.AUTOMATIC: set = _set_icon func _ready(): ProjectSettings.settings_changed.connect(_update_events) _update_events() _update_icon() func _set_action(new_action: String): action = new_action _update_events() _update_icon() func _set_icon(new_icon): icon = new_icon _update_icon() func _update_events(): # In the Editor, InputMap reflects Editor settings # Read the list of actions from ProjectSettings instead # TODO: Find a cleaner way to cast these values var tmp: Array = [] if Engine.is_editor_hint(): tmp = ProjectSettings.get_setting("input/" + action)["events"] else: tmp = InputMap.action_get_events(action) events = [] for ev in tmp: events.append(ev) update_configuration_warnings() func _find_event(list: Array, types: Array): for candidate in list: for type in types: if is_instance_of(candidate, type): return candidate return null func _update_icon(): # If icon is set to AUTOMATIC, first determine which icon to display var display_icon: int = icon if icon == Icons.AUTOMATIC: display_icon = PromptManager.icons # Choose the atlas and region associated with the InputEvent # If the InputMap contains multiple events, choose the first if display_icon == Icons.KEYBOARD: var types = [InputEventKey, InputEventMouseButton] var ev = _find_event(events, types) if ev is InputEventKey: var textures := PromptManager.get_keyboard_textures() texture = textures.get_texture(ev) elif ev is InputEventMouseButton: var textures := PromptManager.get_mouse_textures() texture = textures.get_texture(ev) else: var types = [InputEventJoypadButton, InputEventJoypadMotion] var ev = _find_event(events, types) if ev is InputEventJoypadButton: var textures := PromptManager.get_joypad_button_textures(display_icon) texture = textures.get_texture(ev) elif ev is InputEventJoypadMotion: var textures := PromptManager.get_joypad_motion_textures(display_icon) texture = textures.get_texture(ev) queue_redraw() func _refresh(): _update_events() _update_icon() func _input(event: InputEvent): if not event.is_action_pressed(action): return emit_signal("pressed") func _get_property_list(): var properties = [] properties.append( { name = "ActionPrompt", type = TYPE_NIL, usage = PROPERTY_USAGE_CATEGORY | PROPERTY_USAGE_SCRIPT_VARIABLE } ) # In the Editor, InputMap reflects Editor settings # Read the list of actions from ProjectSettings instead var actions: String = "" for property in ProjectSettings.get_property_list(): var name = property["name"] if name.begins_with("input/"): if actions != "": actions += "," actions += name.trim_prefix("input/") properties.append( {name = "action", type = TYPE_STRING, hint = PROPERTY_HINT_ENUM, hint_string = actions} ) properties.append( { name = "icon", type = TYPE_INT, hint = PROPERTY_HINT_ENUM, hint_string = "Automatic,Xbox,Sony,Nintendo,Keyboard" } ) return properties func _get_configuration_warnings() -> PackedStringArray: var warnings: PackedStringArray = [] # Check that the action is associated with Keyboard/Mouse in the InputMap if icon == Icons.AUTOMATIC or icon == Icons.KEYBOARD: var types = [InputEventKey, InputEventMouseButton] var ev = _find_event(events, types) if not (ev is InputEventKey or ev is InputEventMouseButton): warnings.append("No Key/Mouse input for " + action + " in InputMap.") # Check that the action is associated with Joypad in the InputMap if icon == Icons.AUTOMATIC or icon != Icons.KEYBOARD: var types = [InputEventJoypadButton, InputEventJoypadMotion] var ev = _find_event(events, types) if not (ev is InputEventJoypadButton or ev is InputEventJoypadMotion): warnings.append("No Joypad input for " + action + " in InputMap.") return warnings