diff --git a/scenes/game_elements/props/sign/components/sign.gd b/scenes/game_elements/props/sign/components/sign.gd index 541fc6883..4ae15e38d 100644 --- a/scenes/game_elements/props/sign/components/sign.gd +++ b/scenes/game_elements/props/sign/components/sign.gd @@ -8,6 +8,11 @@ enum Frame { LEFT_AND_RIGHT = 1, } +## Font for the label when [member Settings.large_text] is on. It's +## Jersey 15 instead of Jersey 10, at the size where it's crisp. +const LARGE_TEXT_FONT := preload("uid://db8kp7xkv7gyn") +const LARGE_TEXT_FONT_SIZE := 27 + @export var direction: Enums.LookAtSide = Enums.LookAtSide.LEFT: set(a_direction): direction = a_direction @@ -28,6 +33,10 @@ func _ready() -> void: if Engine.is_editor_hint(): return + if Settings.large_text: + %Label.add_theme_font_override(&"font", LARGE_TEXT_FONT) + %Label.add_theme_font_size_override(&"font_size", LARGE_TEXT_FONT_SIZE) + update_label_visiblity() diff --git a/scenes/globals/settings/settings.gd b/scenes/globals/settings/settings.gd index ffdccd722..2524069ee 100644 --- a/scenes/globals/settings/settings.gd +++ b/scenes/globals/settings/settings.gd @@ -12,6 +12,7 @@ const VOLUME_SECTION := "Volume" const DISPLAY_SECTION := "Display" const SHOW_HUD_KEY := "Show HUD" +const LARGE_TEXT_KEY := "Large Text" const LANGUAGE_SECTION := "Language" const LOCALE_KEY := "Locale" @@ -23,6 +24,10 @@ const MINIMUM_ASPECT_RATIO := 1.25 ## An arbitrary wide ratio, lower than 21:9 ("ultrawide"). const MAXIMUM_ASPECT_RATIO := 2.2 +## Screens whose shortest side is under this are considered small, like phones. +## This is the threshold that Android uses to tell phones from tablets. +const SMALL_SCREEN_SHORTEST_SIDE_DP := 600.0 + @export var fullscreen: bool: get = is_fullscreen, set = set_fullscreen @@ -34,6 +39,15 @@ const MAXIMUM_ASPECT_RATIO := 2.2 _settings.set_value(DISPLAY_SECTION, SHOW_HUD_KEY, new_value) _save() +## Show the text of dialogues and signs with a bigger font. Unless the player +## changes it, this is on for small screens like phones, and off otherwise. +@export var large_text: bool: + get: + return _settings.get_value(DISPLAY_SECTION, LARGE_TEXT_KEY, is_small_screen()) + set(new_value): + _settings.set_value(DISPLAY_SECTION, LARGE_TEXT_KEY, new_value) + _save() + var _settings := ConfigFile.new() var _overrides_path: String @@ -124,6 +138,25 @@ func set_fullscreen(toggled_on: bool) -> void: set_window_mode(DisplayServer.WINDOW_MODE_WINDOWED) +## Return true on touchscreen devices with a small screen, like phones, and +## false on tablets and desktops. +func is_small_screen() -> bool: + if not DisplayServer.is_touchscreen_available(): + return false + var screen_size := Vector2(DisplayServer.screen_get_size()) + var shortest_side := minf(screen_size.x, screen_size.y) + var shortest_side_dp: float + if OS.has_feature("web"): + # On the web, the screen size divided by the scale is in CSS pixels, + # which are close to density-independent pixels. The DPI can't be used, + # because browsers derive it from the scale instead of the real screen. + shortest_side_dp = shortest_side / DisplayServer.screen_get_scale() + else: + # Density-independent pixels are 1/160 inch. + shortest_side_dp = shortest_side * 160.0 / DisplayServer.screen_get_dpi() + return shortest_side_dp < SMALL_SCREEN_SHORTEST_SIDE_DP + + func get_locale() -> String: return TranslationServer.get_locale() diff --git a/scenes/menus/options/components/video_settings.tscn b/scenes/menus/options/components/video_settings.tscn index 3cd33d176..36b93548a 100644 --- a/scenes/menus/options/components/video_settings.tscn +++ b/scenes/menus/options/components/video_settings.tscn @@ -51,6 +51,13 @@ text = "Fullscreen" script = ExtResource("2_qb52c") setting = &"fullscreen" +[node name="LargeTextButton" type="CheckButton" parent="VBoxContainer/GridContainer" unique_id=1394617293] +layout_mode = 2 +size_flags_horizontal = 3 +text = "Large Text" +script = ExtResource("2_qb52c") +setting = &"large_text" + [node name="BackButton" type="Button" parent="VBoxContainer" unique_id=1300000002] unique_name_in_owner = true layout_mode = 2 diff --git a/scenes/ui_elements/dialogue/components/balloon.gd b/scenes/ui_elements/dialogue/components/balloon.gd index 7ccc10719..a37f101b9 100644 --- a/scenes/ui_elements/dialogue/components/balloon.gd +++ b/scenes/ui_elements/dialogue/components/balloon.gd @@ -7,6 +7,10 @@ extends CanvasLayer const PLAYER_RIBBON_TYPE_VARIATION := &"PlayerRibbon" const NPC_RIBBON_TYPE_VARIATION := &"NPCRibbon" +## Theme with a bigger font, used when [member Settings.large_text] is +## on. It uses Jersey 20 instead of Jersey 15, so it's still crisp. +const LARGE_TEXT_THEME := preload("uid://nymvlhys46nm") + ## The dialogue resource @export var dialogue_resource: DialogueResource @@ -101,6 +105,8 @@ var _player_name: String = Player.DEFAULT_PLAYER_NAME func _ready() -> void: if Engine.is_editor_hint(): return + if Settings.large_text: + balloon.theme = LARGE_TEXT_THEME balloon.hide() Engine.get_singleton("DialogueManager").mutated.connect(_on_mutated) diff --git a/scenes/ui_elements/dialogue/components/large_text_theme.tres b/scenes/ui_elements/dialogue/components/large_text_theme.tres new file mode 100644 index 000000000..4d9c723c2 --- /dev/null +++ b/scenes/ui_elements/dialogue/components/large_text_theme.tres @@ -0,0 +1,7 @@ +[gd_resource type="Theme" format=3 uid="uid://nymvlhys46nm"] + +[ext_resource type="FontFile" uid="uid://c3bb7lmvdqc5e" path="res://assets/third_party/fonts/jersey/Jersey20-Regular.ttf" id="1_7a9qj"] + +[resource] +default_font = ExtResource("1_7a9qj") +default_font_size = 34