class_name CharacterCard extends Panel ## One character in the character select popup: its picture and name. Clicking it picks ## the character. ## Emitted with the character's picture when the card is clicked. signal new_character_selected(img_texture: ImageTexture) @onready var character_image: TextureRect = %CharacterTextureRect @onready var character_name_label: Label = %CharacterName func _ready() -> void: gui_input.connect(_on_gui_input) mouse_entered.connect(_set_hovered.bind(true)) mouse_exited.connect(_set_hovered.bind(false)) ## Shows [param character_name] and fetches its picture from the server. func set_character_name(character_name: String) -> void: character_name_label.text = display_name(character_name) tooltip_text = character_name_label.text var image_fetched: Callable = func image_fetched(image: PackedByteArray) -> void: var picture: Image = image_from_bytes(image) if picture == null: GameLog.warning("Could not load the picture of ", character_name) return character_image.texture = ImageTexture.create_from_image(picture) MusicServerClient.fetch_character_image(character_name, image_fetched) ## The name to show for a picture's [param file_name]: without the file extension, and ## with words that are written together split, e.g. "PaperMario.png" is "Paper Mario". static func display_name(file_name: String) -> String: var name_part: String = file_name.get_basename() if "." in file_name else file_name var words: RegEx = RegEx.create_from_string("([a-z])([A-Z])") return words.sub(name_part, "$1 $2", true) ## Reads a PNG, JPG or WebP picture, telling them apart by their first bytes so that no ## error is printed for trying the wrong format. Returns null if it is none of them. static func image_from_bytes(bytes: PackedByteArray) -> Image: var image: Image = Image.new() var error: Error = ERR_FILE_UNRECOGNIZED if bytes.size() >= 4 && bytes.slice(0, 4) == PackedByteArray([0x89, 0x50, 0x4E, 0x47]): error = image.load_png_from_buffer(bytes) elif bytes.size() >= 3 && bytes.slice(0, 3) == PackedByteArray([0xFF, 0xD8, 0xFF]): error = image.load_jpg_from_buffer(bytes) elif bytes.size() >= 12 && bytes.slice(8, 12).get_string_from_ascii() == "WEBP": error = image.load_webp_from_buffer(bytes) return image if error == OK else null func _set_hovered(hovered: bool) -> void: theme_type_variation = &"CharacterCardHover" if hovered else &"CharacterCard" func _on_gui_input(event: InputEvent) -> void: if event is InputEventMouseButton && event.pressed \ && event.button_index == MOUSE_BUTTON_LEFT && Settings.character_select_open: accept_event() GameLog.debug(character_name_label.text) new_character_selected.emit(character_image.texture)