From 9d57763f131f8a4a9ce4ec4f399e9a24c9895a62 Mon Sep 17 00:00:00 2001 From: Iskander Sharipov Date: Fri, 5 Apr 2024 23:46:43 +0400 Subject: [PATCH] add a scaled font accessibility option --- src/assets/_data/raw/en.txt | 4 +- src/assets/_data/raw/en_drones.txt | 32 +-- src/assets/_data/raw/ru.txt | 12 +- src/assets/_data/raw/ru_drones.txt | 62 ++--- src/assets/font.go | 108 +-------- src/assets/monofont/1_00.data.gz | Bin 0 -> 957 bytes src/assets/monofont/1_30.data.gz | Bin 0 -> 1020 bytes src/assets/monofont/bitmap_font.go | 139 +++++++++++ src/assets/monofont/bitmap_image.go | 61 +++++ src/assets/monofont/fontface.go | 221 ++++++++++++++++++ src/assets/monofont/gz.go | 21 ++ src/assets/monofont/scale.go | 130 +++++++++++ src/contentlock/contentlock.go | 1 + src/gamedata/drone_stats.go | 2 +- src/gamedata/version.go | 2 + src/gameui/eui/ebitenui.go | 34 ++- src/go.mod | 1 - src/scenes/menus/bootload.go | 16 +- src/scenes/menus/controls_gamepad.go | 5 +- src/scenes/menus/controls_keyboardmenu.go | 5 +- src/scenes/menus/controls_prompt.go | 5 +- src/scenes/menus/controls_touchmenu.go | 5 +- src/scenes/menus/controlsmenu.go | 3 +- src/scenes/menus/creditsmenu.go | 5 +- src/scenes/menus/glyphcache_controller.go | 3 +- src/scenes/menus/leaderboard_browser.go | 6 +- src/scenes/menus/leaderboard_loading.go | 5 +- src/scenes/menus/leaderboardmenu.go | 3 +- src/scenes/menus/lobbymenu.go | 14 +- src/scenes/menus/mainmenu.go | 2 +- src/scenes/menus/options_accessibilitymenu.go | 98 ++++++++ src/scenes/menus/options_extramenu.go | 18 +- src/scenes/menus/options_gameplaymenu.go | 3 +- src/scenes/menus/options_graphicsmenu.go | 2 +- src/scenes/menus/options_soundmenu.go | 2 +- src/scenes/menus/optionsmenu.go | 11 +- src/scenes/menus/panic_controller.go | 2 +- src/scenes/menus/playmenu.go | 4 +- src/scenes/menus/profile_achievementsmenu.go | 5 +- .../menus/profile_dronecollectionmenu.go | 5 +- src/scenes/menus/profile_progressmenu.go | 5 +- src/scenes/menus/profile_statsmenu.go | 5 +- src/scenes/menus/profilemenu.go | 3 +- src/scenes/menus/replaymenu.go | 4 +- src/scenes/menus/schemamenu.go | 5 +- src/scenes/menus/schemanamemenu.go | 2 +- src/scenes/menus/secretmenu.go | 4 +- src/scenes/menus/splashscreen.go | 4 +- src/scenes/menus/submit_screen.go | 5 +- src/scenes/menus/terminalmenu.go | 4 +- src/scenes/menus/usernamemenu.go | 4 +- src/scenes/staging/arena_manager.go | 2 +- src/scenes/staging/debug_drone_label_node.go | 2 +- src/scenes/staging/message_manager.go | 11 +- src/scenes/staging/message_node.go | 18 +- src/scenes/staging/results_controller.go | 5 +- src/scenes/staging/rewards_controller.go | 4 +- src/scenes/staging/staging_controller.go | 8 +- src/scenes/staging/tooltip_manager.go | 4 +- src/scenes/staging/tutorial_manager.go | 2 +- src/scenes/staging/world_state.go | 4 + src/session/state.go | 30 ++- 62 files changed, 892 insertions(+), 300 deletions(-) create mode 100644 src/assets/monofont/1_00.data.gz create mode 100644 src/assets/monofont/1_30.data.gz create mode 100644 src/assets/monofont/bitmap_font.go create mode 100644 src/assets/monofont/bitmap_image.go create mode 100644 src/assets/monofont/fontface.go create mode 100644 src/assets/monofont/gz.go create mode 100644 src/assets/monofont/scale.go create mode 100644 src/scenes/menus/options_accessibilitymenu.go diff --git a/src/assets/_data/raw/en.txt b/src/assets/_data/raw/en.txt index d4a483ff..763a8377 100644 --- a/src/assets/_data/raw/en.txt +++ b/src/assets/_data/raw/en.txt @@ -128,6 +128,7 @@ Schemas can be used to save and load your favorite drone build. ##menu.options.sound : Sound ##menu.options.graphics : Graphics ##menu.options.extra : Extra +##menu.options.accessibility : Accessibility ##menu.options.controls : Controls ##menu.options.music_player : Music player @@ -179,6 +180,7 @@ Schemas can be used to save and load your favorite drone build. ##menu.options.scroll_speed : Scroll speed ##menu.options.edge_scroll_range : Edge scroll range ##menu.options.large_diodes : Large diodes +##menu.options.larger_font : Larger font ##menu.options.show_fps : Show FPS ##menu.options.show_timer : Show timer ##menu.options.splash_screen : Splash screen @@ -536,7 +538,7 @@ Win by surviving for 20 waves. Split-screen multiplayer: cooperative. ##menu.overview.inf_arena -Infinite arena mode (est. time: 90 minutes) +Inf arena mode (est. time: 90 minutes) Stand the ground for as long as possible. diff --git a/src/assets/_data/raw/en_drones.txt b/src/assets/_data/raw/en_drones.txt index 42018291..db309978 100644 --- a/src/assets/_data/raw/en_drones.txt +++ b/src/assets/_data/raw/en_drones.txt @@ -23,7 +23,7 @@ ##core.ability.weapons : Can attack flying targets ##core.ability.ground_weapons : Can attack ground targets ##core.ability.robust : Highly resistant to damage -##core.ability.cheap_drones : Drone production takes less resources +##core.ability.cheap_drones : Cheaper drone production ##drone.kind.worker : worker ##drone.kind.military : combat @@ -80,38 +80,38 @@ ##drone.ability.self_repair : Repairs itself over time ##drone.ability.extra_payload : Increased max payload -##drone.ability.aggro : Forces the target to attack this drone +##drone.ability.aggro : Attracts the target's aggro ##drone.ability.disarm : May disable the target's weapon ##drone.ability.slow : Slows targets down ##drone.ability.cloak_hide : Cloaks itself when heavily damaged ##drone.ability.cloak_scavenge : Cloaks itself when harvesting scraps ##drone.ability.energy_regen : Very high energy regen rate -##drone.ability.cloning : Performs cloning of non-elite drones +##drone.ability.cloning : Performs drone cloning ##drone.ability.repair : Repairs damaged drones -##drone.ability.recharge : Recovers the energy of the nearby drones +##drone.ability.recharge : Recovers the energy of drones ##drone.ability.red_oil_scavenge : Can harvest a red oil resource ##drone.ability.colony_speed : Makes the colony move faster ##drone.ability.colony_jump : Increases colony max jump distance ##drone.ability.discharged_speed : Moves fast even when low on energy ##drone.ability.scrap_scavenge : Can harvest scraps -##drone.ability.courier : Distributes the resources between colonies +##drone.ability.courier : Redistributes colony resources ##drone.ability.zero_upkeep : Zero upkeep cost ##drone.ability.upkeep_decrease : Decreases the total upkeep costs ##drone.ability.ground : The only ground drone ##drone.ability.map_patrol : Patrols the map and guards turrets -##drone.ability.discharged_after_attack : Completely discharges after firing its weapon -##drone.ability.group_command : Takes command of several combat drones -##drone.ability.group_buff : Improves the firing accuracy of its group -##drone.ability.group_buff_def : Improves the durability of its group -##drone.ability.target_marking : Makes targets attackable from a longer distance -##drone.ability.kamikaze : Becomes a kamikaze drone if heavily damaged -##drone.ability.prism_reflect : Combines attacks with nearby prisms -##drone.ability.scarab_potential : Has the potential to become something more -##drone.ability.consume_for_heal : Consumes tier 1 workers to repair itself -##drone.ability.consume_for_power : Gets permanent power when consuming a drone +##drone.ability.discharged_after_attack : Discharges after firing once +##drone.ability.group_command : Followed by other drones +##drone.ability.group_buff : Improves the group's accuracy +##drone.ability.group_buff_def : Improves the group's durability +##drone.ability.target_marking : Increases range by marking targets +##drone.ability.kamikaze : Can perform a kamikaze attack +##drone.ability.prism_reflect : Prisms combine their attacks +##drone.ability.scarab_potential : Greatly evolves over time +##drone.ability.consume_for_heal : Consumes t1 workers to repair itself +##drone.ability.consume_for_power : Gets power when consuming a drone ##drone.ability.bomb_attack : Attacks only when ordered -##drone.ability.bomb_aoe : The bombs deal massive area of effect damage +##drone.ability.bomb_aoe : The bombs deal area of effect damage ##drone.ability.more_building_damage_f : %d%% more damage against buildings ##drone.ability.less_building_damage_f : %d%% less damage against buildings diff --git a/src/assets/_data/raw/ru.txt b/src/assets/_data/raw/ru.txt index 041565d0..4cad0519 100644 --- a/src/assets/_data/raw/ru.txt +++ b/src/assets/_data/raw/ru.txt @@ -128,6 +128,7 @@ ##menu.options.sound : Звук ##menu.options.graphics : Графика ##menu.options.extra : Дополнительно +##menu.options.accessibility : Доступность ##menu.options.controls : Управление ##menu.options.music_player : Формат музыки @@ -180,6 +181,7 @@ ##menu.options.scroll_speed : Скорость скроллинга ##menu.options.edge_scroll_range : Ширина границы прокрутки ##menu.options.large_diodes : Крупные диоды +##menu.options.larger_font : Крупный текст ##menu.options.show_fps : Отображать FPS ##menu.options.show_timer : Отображать таймер ##menu.options.splash_screen : Экран заставки @@ -504,14 +506,14 @@ x1.5 означает, что игра будет работать на 50% бы Показать подсказку | Длительное касание на точке интереса ##menu.overview.intro_mission -Вступительная миссия (время прохождения: ~15 минут) +Вступительная миссия (~15 минут) Режим с подсказками и постановочными ситуациями. Он позволит изучить основы геймплея и научиться защищать свою колонию. Выполнение этой миссии откроет доступ к классическому режиму (альтернатива: 1-2 победы в Блиц режиме). ##menu.overview.classic -Классический режим (время прохождения: ~30 минут) +Классический режим (~30 минут) Победа в этом режиме достигается путём уничтожения вражеского флагмана - дредноута. Это основной режим игры. @@ -520,7 +522,7 @@ x1.5 означает, что игра будет работать на 50% бы Мультиплеер с разделённым экраном: кооперативный. ##menu.overview.blitz -Блиц режим (время прохождения: ~15 минут) +Блиц режим (~15 минут) Уничтожьте все постройки, производящие вражеских юнитов. Этот режим больше подходит для новичков, чем Классический. @@ -529,7 +531,7 @@ x1.5 означает, что игра будет работать на 50% бы Мультиплеер с разделённым экраном: кооперативный. ##menu.overview.arena -Режим арены (время прохождения: 60 минут) +Режим арены (60 минут) Выдержите 20 волн атак. @@ -545,7 +547,7 @@ x1.5 означает, что игра будет работать на 50% бы Мультиплеер с разделённым экраном: кооперативный. ##menu.overview.reverse -Реверсивный режим (время прохождения: ~40 минут) +Реверсивный режим (~40 минут) Поменяйтесь местами и сыграйте за дредноута. diff --git a/src/assets/_data/raw/ru_drones.txt b/src/assets/_data/raw/ru_drones.txt index 857e0eeb..0b780e9c 100644 --- a/src/assets/_data/raw/ru_drones.txt +++ b/src/assets/_data/raw/ru_drones.txt @@ -10,21 +10,21 @@ ##core.tank : Бастион ##core.hive : Улий -##core.mobility_rating : Рейтинг мобильности -##core.unit_limit_rating : Рейтинг количества дронов -##core.capacity_rating : Рейтинг вместимости ресурсов +##core.mobility_rating : Мобильность +##core.unit_limit_rating : Количество дронов +##core.capacity_rating : Вместимость -##core.ability.crush : Может разрушать наземных юнитов при посадке -##core.ability.build_discount : Тратит на 50% меньше ресурсов на строительство +##core.ability.crush : Посадка разрушает наземных юнитов +##core.ability.build_discount : Строительство на 50% дешевле ##core.ability.flying : Воздушная колония ##core.ability.no_teleporters : Не может использовать телепортеры ##core.ability.cant_fly : Не может летать ##core.ability.cant_move : Не может перемещаться -##core.ability.drone_control : Может устанавливать точки сбора дронов +##core.ability.drone_control : Задаёт точки сбора дронов ##core.ability.weapons : Атакует воздушные цели ##core.ability.ground_weapons : Атакует наземные цели ##core.ability.robust : Блокирует часть наносимого урона -##core.ability.cheap_drones : Производство дронов требует меньше ресурсов +##core.ability.cheap_drones : Дешёвое производство дронов ##drone.kind.worker : рабочий ##drone.kind.military : военный @@ -71,46 +71,46 @@ ##drone.attack_rating_multi : на 1 цель ##drone.ability.num_targets_f : Атакует до %d целей -##drone.ability.num_targets_alt_f : До %d дополнительных целей вокруг основной +##drone.ability.num_targets_alt_f : До %d доп целей вокруг основной -##drone.dps_rating : Рейтинг урона в секунду -##drone.attack_range_rating : Рейтинг дальности атаки -##drone.defense_rating : Рейтинг защиты -##drone.attack_rating : Рейтинг вооружения +##drone.dps_rating : Атака +##drone.attack_range_rating : Дальности атаки +##drone.defense_rating : Защита +##drone.attack_rating : Вооружение ##drone.upkeep_cost : Цена обслуживания ##drone.ability.self_repair : Имеет функцию саморемонта ##drone.ability.extra_payload : Увеличенный трюм -##drone.ability.aggro : Заставляет целей атаковать этого дрона +##drone.ability.aggro : Заставляет целей атаковать себя ##drone.ability.disarm : Может отключать оружие своих целей ##drone.ability.slow : Замедляет цели -##drone.ability.cloak_hide : Уходит в невидимость при высокой опасности +##drone.ability.cloak_hide : Защитная невидимость ##drone.ability.cloak_scavenge : Добывает ресурсы в невидимости -##drone.ability.energy_regen : Высокая скорость восстановления энергии -##drone.ability.cloning : Клонирует других дронов (кроме элитных) +##drone.ability.energy_regen : Почти бесконечная энергия +##drone.ability.cloning : Клонирует других дронов ##drone.ability.repair : Чинит повреждённых дронов -##drone.ability.recharge : Восстанавливает энергию ближайшим дронам +##drone.ability.recharge : Восстанавливает энергию дронам ##drone.ability.red_oil_scavenge : Может добывать алую нефть ##drone.ability.colony_speed : Ускоряет колонию -##drone.ability.colony_jump : Увеличивает дальность прыжка колонии -##drone.ability.discharged_speed : Быстро перемещается даже при низком заряде +##drone.ability.colony_jump : Увеличивает радиус прыжка колонии +##drone.ability.discharged_speed : Не замедляется от разрядки ##drone.ability.scrap_scavenge : Может собирать обломки -##drone.ability.courier : Перераспределяет ресурсы между колониями +##drone.ability.courier : Распределяет ресурсы между базами ##drone.ability.zero_upkeep : Нулевая цена обслужевания -##drone.ability.upkeep_decrease : Снижает расходы на обслуживание дронов колонии +##drone.ability.upkeep_decrease : Понижает расходы колонии ##drone.ability.ground : Единственный наземный дрон ##drone.ability.map_patrol : Патрулирует карту, охраняет турели -##drone.ability.discharged_after_attack : Разряжается после использования оружия -##drone.ability.group_command : Берёт под контроль несколько боевых дронов -##drone.ability.group_buff : Улучшает меткость стрельбы своей группы -##drone.ability.group_buff_def : Увеличивает прочность дронов группы -##drone.ability.target_marking : Размеченные им цели можно атаковать издалека -##drone.ability.kamikaze : Перед смертью бросается в последний рывок -##drone.ability.prism_reflect : Атаки близкостоящих призм объединяются -##drone.ability.scarab_potential : Имеет потенциал стать чем-то более сильным -##drone.ability.consume_for_heal : Поглощает рабочих 1 тира для саморемонта -##drone.ability.consume_for_power : Получает постоянные бонусы при таком поглощении +##drone.ability.discharged_after_attack : Разряжается после выстрела +##drone.ability.group_command : Управляет группой дронов +##drone.ability.group_buff : Улучшает меткость стрельбы группы +##drone.ability.group_buff_def : Увеличивает прочность группы +##drone.ability.target_marking : Размечает цели для дальней атаки +##drone.ability.kamikaze : Умирая, выполняет финальную атаку +##drone.ability.prism_reflect : Атаки призм объединяются +##drone.ability.scarab_potential : Усиливается со временем +##drone.ability.consume_for_heal : Поглощает т1 рабочих для ремонта +##drone.ability.consume_for_power : Получает бонусы при поглощении ##drone.ability.bomb_attack : Атакует только по приказу ##drone.ability.bomb_aoe : Бомбы наносят высокий урон по области ##drone.ability.more_building_damage_f : На %d%% больше урона по зданиям diff --git a/src/assets/font.go b/src/assets/font.go index ff4581bc..dd876617 100644 --- a/src/assets/font.go +++ b/src/assets/font.go @@ -1,109 +1,13 @@ package assets import ( - "image" - "image/color" - - "github.com/hajimehoshi/bitmapfont/v3" - "golang.org/x/image/font" - "golang.org/x/image/math/fixed" + "github.com/quasilyte/roboden-game/assets/monofont" ) var ( - BitmapFont1 = bitmapfont.Face - BitmapFont2 = scaleFont(BitmapFont1, 2) - BitmapFont3 = scaleFont(BitmapFont1, 3) -) - -func euclidianDiv(x, y int) int { - if x < 0 { - x -= y - 1 - } - return x / y -} - -type scaledImage struct { - image image.Image - scale int -} - -func (s *scaledImage) ColorModel() color.Model { - return s.image.ColorModel() -} - -func (s *scaledImage) Bounds() image.Rectangle { - b := s.image.Bounds() - b.Min = b.Min.Mul(s.scale) - b.Max = b.Max.Mul(s.scale) - return b -} - -func (s *scaledImage) At(x, y int) color.Color { - x = euclidianDiv(x, s.scale) - y = euclidianDiv(y, s.scale) - return s.image.At(x, y) -} - -func scaleFont(f font.Face, scale int) font.Face { - if scale == 1 { - return f - } - return &scaledFont{f, scale} -} + Font1 = monofont.New1() + Font2 = monofont.Scale(Font1, 2) + Font3 = monofont.Scale(Font1, 3) -type scaledFont struct { - font font.Face - scale int -} - -func (s *scaledFont) Close() error { - return s.font.Close() -} - -func (s *scaledFont) Glyph(dot fixed.Point26_6, r rune) (dr image.Rectangle, mask image.Image, maskp image.Point, advance fixed.Int26_6, ok bool) { - dr, mask, maskp, advance, ok = s.font.Glyph(dot, r) - if !ok { - return - } - d := image.Pt(dot.X.Floor(), dot.Y.Floor()) - dr.Min = dr.Min.Sub(d).Mul(s.scale).Add(d) - dr.Max = dr.Max.Sub(d).Mul(s.scale).Add(d) - maskp = maskp.Mul(s.scale) - advance *= fixed.Int26_6(s.scale) - return dr, &scaledImage{mask, s.scale}, maskp, advance, ok -} - -func (s *scaledFont) GlyphBounds(r rune) (bounds fixed.Rectangle26_6, advance fixed.Int26_6, ok bool) { - bounds, advance, ok = s.font.GlyphBounds(r) - if !ok { - return - } - bounds.Min.X *= fixed.Int26_6(s.scale) - bounds.Min.Y *= fixed.Int26_6(s.scale) - bounds.Max.X *= fixed.Int26_6(s.scale) - bounds.Max.Y *= fixed.Int26_6(s.scale) - advance *= fixed.Int26_6(s.scale) - return -} - -func (s *scaledFont) GlyphAdvance(r rune) (advance fixed.Int26_6, ok bool) { - advance, ok = s.font.GlyphAdvance(r) - if !ok { - return - } - advance *= fixed.Int26_6(s.scale) - return -} - -func (s *scaledFont) Kern(r0, r1 rune) fixed.Int26_6 { - return s.font.Kern(r0, r1) * fixed.Int26_6(s.scale) -} - -func (s *scaledFont) Metrics() font.Metrics { - m := s.font.Metrics() - return font.Metrics{ - Height: m.Height * fixed.Int26_6(s.scale), - Ascent: m.Ascent * fixed.Int26_6(s.scale), - Descent: m.Descent * fixed.Int26_6(s.scale), - } -} + Font1_3 = monofont.New1_3() +) diff --git a/src/assets/monofont/1_00.data.gz b/src/assets/monofont/1_00.data.gz new file mode 100644 index 0000000000000000000000000000000000000000..2629bc3e47f2f7d2c8cdfff4e3e84882f35386d5 GIT binary patch literal 957 zcmV;u148^CiwFP!00000|Ll}OZyQAv$Ny`O*{xNjQ#`4AYS*$6_N_f2H4;L*PNwOC z>SP;FsvJm!gpXVhmx>vCmtg8+E43^R3M@!R351h%px6*)cp<9+Y&TJ zs_b`F^zrn~l-VzOl-Z#2tWxS*S;njOMfB!rRiyOrpgGMLvtK}@TIJ_W+oDyrhe@#- z$@>M(6%0-g$)L~=rNF|#rv9R(7Q@`|M zopu3W^P0Y)mLe&R6n!8fyyDczaCs2k8(oj2NN%e{Ad6>00q+=N1O?M7>ZR=}v8MEz zq|~<3H%J&9Dft38=@?t};@+EpvZEU`6SzO$u_i;B|5xZSaTOEi;ehZmCjW$I$7;%#hBs z53kNma%O)Qr(I)~Y-Z+-Q6m{Oe(_`Sj~`1x6B=V)_<2wphrytpjI75Ve%<@ST4MUi z{phJ5|Lh@pU|tww3dpK@xSF^PI{)B|{4-tU#fmf1&TNC9TYct60?glcjNM>o61hzJ zmDv!$$t(cU4;!wdy2!!QiPFbu;m48t%C!!QiPFbu;m f48t%C!!XSMh<^b90RR6100960!NA(Yur2@qG2z{O literal 0 HcmV?d00001 diff --git a/src/assets/monofont/1_30.data.gz b/src/assets/monofont/1_30.data.gz new file mode 100644 index 0000000000000000000000000000000000000000..c9ffaa0c6d64b1917b7458fd902b9970ff56b15f GIT binary patch literal 1020 zcmbWni&N4E0KoBI4Nk>Lx$=>9l5>*Qnpme~YIv8=rP(yIe5|H8#|+K4sDVavZDQ1E z7H9Ku+RO(M+NmU`D-}-N#Im6V0s2$vL`5J(e>{G>>rdGCKKI2`Sp%Pf*Xkr$px@rg z(8~HJcJ6hEl)3Vwc|X~*tNosq%sAq@JP+#InELt5V zPpl6mLQVtMq`=c;)YN5WPIgO}7qWUVc&L4%=YuY=2xM?ETO|H2!5kVWlL`?bbC{+` za2xbsGk-H?AHa@ixY+(^yuc^mNc~ddD#-x%k|oCpX(m;SmEE)?&PPUKA0*HJkes

N~ugxgy~A}T(DUnh6P?mRK<@sN(8GKw*oUJl~k)|iaf!sw4l1Aow%ms4SC zcWe95H+@KP4)sd+rF5Ga{jm9v!&2fMj#?ml3(faLuH&s2Us`0)ytaH2KJh-9VwEy} zLEjVd*?Cj3GTRZluQN#1K_PTr$-@R28D|*uS-Cg~5g8ij!nfpDc=v}FAeU??9ptmd z3>FKhFjg_u=9?12ie;n5t;RXaM3sob(l*RpB5tDg*5cr84Ubk8!Gutg^mkFj$3pKy zK}OOXw7Ioah)#8p!F~Kv|JoWyv-W2=ngIJzU-A9&eg&Voisk2IY!*<##?cZ&! zmG6)9=xa`T-2LD?Dw0`g1~~a0Y+#Ynv^p;LHh%S f.MaxRune || r < f.MinRune { + return dr, mask, advance, false + } + + // Map rune to its index inside the associated data. + index, ok := f.getRuneIndex(r) + if !ok { + if panicOnUndefined { + panic(fmt.Sprintf("requesting an undefined rune %v (%q)", r, r)) + } + return dr, mask, advance, false + } + + rw := f.glyphWidth + rh := f.glyphHeight + dx := (dot.X - f.DotX).Floor() + dy := (dot.Y - f.DotY).Floor() + dr = image.Rect(dx, dy, dx+rw, dy+rh) + + offset := index * f.GlyphBitSize + mask = f.img.WithOffset(offset) + advance = fixed.I(rw) + return dr, mask, advance, true +} + +func (f *bitmapFont) GlyphAdvance(r rune) (advance fixed.Int26_6, ok bool) { + if r > f.MaxRune || r < f.MinRune { + return 0, false + } + return fixed.I(f.glyphWidth), true +} + +func (f *bitmapFont) GlyphBounds(r rune) (bounds fixed.Rectangle26_6, advance fixed.Int26_6, ok bool) { + if r > f.MaxRune || r < f.MinRune { + return bounds, advance, false + } + bounds = fixed.Rectangle26_6{ + Min: fixed.Point26_6{X: -f.DotX, Y: -f.DotY}, + Max: fixed.Point26_6{ + X: -f.DotX + fixed.I(f.glyphWidth), + Y: -f.DotY + fixed.I(f.glyphHeight), + }, + } + advance = fixed.I(f.glyphWidth) + return bounds, advance, true +} + +func (f *bitmapFont) Kern(r0, r1 rune) fixed.Int26_6 { + if unicode.Is(unicode.Mn, r1) { + return -fixed.I(f.glyphWidth) + } + return 0 + +} + +func (f *bitmapFont) Metrics() font.Metrics { + return font.Metrics{ + Height: fixed.I(f.glyphHeight), + Ascent: f.DotY, + Descent: fixed.I(f.glyphHeight) - f.DotY, + } +} + +func (f *bitmapFont) getRuneIndex(r rune) (uint, bool) { + u := uint(r) + slice := f.RuneToIndex + if u < uint(len(slice)) { + i := slice[u] + if i > 0 { + return uint(i - 1), true + } + } + return 0, false +} + +// func (f *Face) Glyph(dot fixed.Point26_6, r rune) (dr image.Rectangle, mask image.Image, maskp image.Point, advance fixed.Int26_6, ok bool) { +// if r >= 0x10000 { +// return +// } + +// rw := f.runeWidth(r) +// dx := (dot.X - f.dotX).Floor() +// dy := (dot.Y - f.dotY).Floor() +// dr = image.Rect(dx, dy, dx+rw, dy+f.charHeight()) + +// mx := (int(r) % charXNum) * f.charFullWidth() +// my := (int(r) / charXNum) * f.charHeight() +// mask = f.image.SubImage(image.Rect(mx, my, mx+rw, my+f.charHeight())) +// maskp = image.Pt(mx, my) +// advance = fixed.I(f.runeWidth(r)) +// ok = true +// return +// } diff --git a/src/assets/monofont/bitmap_image.go b/src/assets/monofont/bitmap_image.go new file mode 100644 index 00000000..ca54f635 --- /dev/null +++ b/src/assets/monofont/bitmap_image.go @@ -0,0 +1,61 @@ +package monofont + +import ( + "image" + "image/color" +) + +var ( + colorZero = color.Alpha{0} + colorOne = color.Alpha{0xff} +) + +type bitmapImage struct { + data []byte + width uint + height uint + offset uint + bounds image.Rectangle +} + +func newBitmapImage(data []byte, w, h int) *bitmapImage { + // data is expected to be uncompressed. + return &bitmapImage{ + width: uint(w), + height: uint(h), + data: data, + bounds: image.Rect(0, 0, w, h), + } +} + +func (img *bitmapImage) WithOffset(offset uint) *bitmapImage { + return &bitmapImage{ + data: img.data, + width: img.width, + offset: offset, + bounds: img.bounds, + } +} + +func (img *bitmapImage) ColorModel() color.Model { + return color.AlphaModel +} + +func (img *bitmapImage) Bounds() image.Rectangle { + return img.bounds +} + +func (img *bitmapImage) At(x, y int) color.Color { + i := (uint(y) * img.width) + uint(x) + img.offset + byteIndex := i / 8 + byteShift := i % 8 + data := img.data + if byteIndex < uint(len(data)) { + b := data[byteIndex] + v := b >> byte(byteShift) & 0b1 + if v == 1 { + return colorOne + } + } + return colorZero +} diff --git a/src/assets/monofont/fontface.go b/src/assets/monofont/fontface.go new file mode 100644 index 00000000..d85ce253 --- /dev/null +++ b/src/assets/monofont/fontface.go @@ -0,0 +1,221 @@ +// Code generated by fontget, DO NOT EDIT + +package monofont + +import ( + _ "embed" + "golang.org/x/image/font" +) + +// New1 allocates a font of size=1. +// +// Allocating several instances of the same-sized font is unadvised +// as they would not share the resources. +func New1() font.Face { + data := uncompress(size1_00data) + img := newBitmapImage(data, 6, 12) + f := newBitmapFont(img, 0, 10) + f.MinRune = 32 + f.MaxRune = 10064 + f.GlyphBitSize = 72 + f.RuneToIndex = runeToIndex[:] + return f +} + +// New1_3 allocates a font of size=1.3. +// +// Allocating several instances of the same-sized font is unadvised +// as they would not share the resources. +func New1_3() font.Face { + data := uncompress(size1_30data) + img := newBitmapImage(data, 8, 16) + f := newBitmapFont(img, 0, 13) + f.MinRune = 32 + f.MaxRune = 10064 + f.GlyphBitSize = 128 + f.RuneToIndex = runeToIndex[:] + return f +} + +var ( + //go:embed 1_00.data.gz + size1_00data []byte + + //go:embed 1_30.data.gz + size1_30data []byte +) + +var ( + runeToIndex = [...]uint16{ + 32: 0 + 1, // ' ' + 33: 1 + 1, // '!' + 34: 2 + 1, // '"' + 35: 3 + 1, // '#' + 36: 4 + 1, // '$' + 37: 5 + 1, // '%' + 38: 6 + 1, // '&' + 39: 7 + 1, // '\'' + 40: 8 + 1, // '(' + 41: 9 + 1, // ')' + 42: 10 + 1, // '*' + 43: 11 + 1, // '+' + 44: 12 + 1, // ',' + 45: 13 + 1, // '-' + 46: 14 + 1, // '.' + 47: 15 + 1, // '/' + 48: 16 + 1, // '0' + 49: 17 + 1, // '1' + 50: 18 + 1, // '2' + 51: 19 + 1, // '3' + 52: 20 + 1, // '4' + 53: 21 + 1, // '5' + 54: 22 + 1, // '6' + 55: 23 + 1, // '7' + 56: 24 + 1, // '8' + 57: 25 + 1, // '9' + 58: 26 + 1, // ':' + 60: 27 + 1, // '<' + 61: 28 + 1, // '=' + 62: 29 + 1, // '>' + 63: 30 + 1, // '?' + 64: 31 + 1, // '@' + 65: 32 + 1, // 'A' + 66: 33 + 1, // 'B' + 67: 34 + 1, // 'C' + 68: 35 + 1, // 'D' + 69: 36 + 1, // 'E' + 70: 37 + 1, // 'F' + 71: 38 + 1, // 'G' + 72: 39 + 1, // 'H' + 73: 40 + 1, // 'I' + 74: 41 + 1, // 'J' + 75: 42 + 1, // 'K' + 76: 43 + 1, // 'L' + 77: 44 + 1, // 'M' + 78: 45 + 1, // 'N' + 79: 46 + 1, // 'O' + 80: 47 + 1, // 'P' + 81: 48 + 1, // 'Q' + 82: 49 + 1, // 'R' + 83: 50 + 1, // 'S' + 84: 51 + 1, // 'T' + 85: 52 + 1, // 'U' + 86: 53 + 1, // 'V' + 87: 54 + 1, // 'W' + 88: 55 + 1, // 'X' + 89: 56 + 1, // 'Y' + 90: 57 + 1, // 'Z' + 91: 58 + 1, // '[' + 92: 59 + 1, // '\\' + 93: 60 + 1, // ']' + 94: 61 + 1, // '^' + 97: 62 + 1, // 'a' + 98: 63 + 1, // 'b' + 99: 64 + 1, // 'c' + 100: 65 + 1, // 'd' + 101: 66 + 1, // 'e' + 102: 67 + 1, // 'f' + 103: 68 + 1, // 'g' + 104: 69 + 1, // 'h' + 105: 70 + 1, // 'i' + 106: 71 + 1, // 'j' + 107: 72 + 1, // 'k' + 108: 73 + 1, // 'l' + 109: 74 + 1, // 'm' + 110: 75 + 1, // 'n' + 111: 76 + 1, // 'o' + 112: 77 + 1, // 'p' + 113: 78 + 1, // 'q' + 114: 79 + 1, // 'r' + 115: 80 + 1, // 's' + 116: 81 + 1, // 't' + 117: 82 + 1, // 'u' + 118: 83 + 1, // 'v' + 119: 84 + 1, // 'w' + 120: 85 + 1, // 'x' + 121: 86 + 1, // 'y' + 122: 87 + 1, // 'z' + 123: 88 + 1, // '{' + 124: 89 + 1, // '|' + 125: 90 + 1, // '}' + 126: 91 + 1, // '~' + 215: 92 + 1, // '×' + 1025: 93 + 1, // 'Ё' + 1040: 94 + 1, // 'А' + 1041: 95 + 1, // 'Б' + 1042: 96 + 1, // 'В' + 1043: 97 + 1, // 'Г' + 1044: 98 + 1, // 'Д' + 1045: 99 + 1, // 'Е' + 1046: 100 + 1, // 'Ж' + 1047: 101 + 1, // 'З' + 1048: 102 + 1, // 'И' + 1049: 103 + 1, // 'Й' + 1050: 104 + 1, // 'К' + 1051: 105 + 1, // 'Л' + 1052: 106 + 1, // 'М' + 1053: 107 + 1, // 'Н' + 1054: 108 + 1, // 'О' + 1055: 109 + 1, // 'П' + 1056: 110 + 1, // 'Р' + 1057: 111 + 1, // 'С' + 1058: 112 + 1, // 'Т' + 1059: 113 + 1, // 'У' + 1060: 114 + 1, // 'Ф' + 1061: 115 + 1, // 'Х' + 1062: 116 + 1, // 'Ц' + 1063: 117 + 1, // 'Ч' + 1064: 118 + 1, // 'Ш' + 1065: 119 + 1, // 'Щ' + 1066: 120 + 1, // 'Ъ' + 1067: 121 + 1, // 'Ы' + 1068: 122 + 1, // 'Ь' + 1069: 123 + 1, // 'Э' + 1070: 124 + 1, // 'Ю' + 1071: 125 + 1, // 'Я' + 1072: 126 + 1, // 'а' + 1073: 127 + 1, // 'б' + 1074: 128 + 1, // 'в' + 1075: 129 + 1, // 'г' + 1076: 130 + 1, // 'д' + 1077: 131 + 1, // 'е' + 1078: 132 + 1, // 'ж' + 1079: 133 + 1, // 'з' + 1080: 134 + 1, // 'и' + 1081: 135 + 1, // 'й' + 1082: 136 + 1, // 'к' + 1083: 137 + 1, // 'л' + 1084: 138 + 1, // 'м' + 1085: 139 + 1, // 'н' + 1086: 140 + 1, // 'о' + 1087: 141 + 1, // 'п' + 1088: 142 + 1, // 'р' + 1089: 143 + 1, // 'с' + 1090: 144 + 1, // 'т' + 1091: 145 + 1, // 'у' + 1092: 146 + 1, // 'ф' + 1093: 147 + 1, // 'х' + 1094: 148 + 1, // 'ц' + 1095: 149 + 1, // 'ч' + 1096: 150 + 1, // 'ш' + 1097: 151 + 1, // 'щ' + 1098: 152 + 1, // 'ъ' + 1099: 153 + 1, // 'ы' + 1100: 154 + 1, // 'ь' + 1101: 155 + 1, // 'э' + 1102: 156 + 1, // 'ю' + 1103: 157 + 1, // 'я' + 1105: 158 + 1, // 'ё' + 9633: 159 + 1, // '□' + 9651: 160 + 1, // '△' + 9675: 161 + 1, // '○' + 9676: 162 + 1, // '◌' + 9679: 163 + 1, // '●' + 9776: 164 + 1, // '☰' + 10064: 165 + 1, // '❐' + } +) + +const ( + panicOnUndefined = false +) diff --git a/src/assets/monofont/gz.go b/src/assets/monofont/gz.go new file mode 100644 index 00000000..a155557a --- /dev/null +++ b/src/assets/monofont/gz.go @@ -0,0 +1,21 @@ +package monofont + +import ( + "bytes" + "compress/gzip" + "fmt" +) + +func uncompress(data []byte) []byte { + gzr, err := gzip.NewReader(bytes.NewReader(data)) + if err != nil { + panic(fmt.Errorf("uncompress: %v", err)) + } + + var uncompressed bytes.Buffer + if _, err := uncompressed.ReadFrom(gzr); err != nil { + panic(fmt.Errorf("uncompress: %v", err)) + } + + return uncompressed.Bytes() +} diff --git a/src/assets/monofont/scale.go b/src/assets/monofont/scale.go new file mode 100644 index 00000000..8e59ccd1 --- /dev/null +++ b/src/assets/monofont/scale.go @@ -0,0 +1,130 @@ +package monofont + +import ( + "fmt" + "image" + "image/color" + + "golang.org/x/image/font" + "golang.org/x/image/math/fixed" +) + +// Scale takes the bitmap font and returns its scaled version. +// Scaling the font is efficient and doesn't extra memory. +// +// A scaling factor of 1 is a no-op. +// A scaling factor of 2 makes the pixels twice as big. +// +// This function will only work with fonts created by +// this package. Any other font will make it panic. +func Scale(f font.Face, scaling uint) font.Face { + if scaling == 0 { + panic("a zero scaling factor is not supported") + } + if scaling == 1 { + return f + } + + bf, ok := f.(*bitmapFont) + if !ok { + panic(fmt.Sprintf("expected a bitmap font, got %T", f)) + } + + return &scaledFont{ + font: bf, + scale: int(scaling), + } +} + +type scaledFont struct { + font *bitmapFont + scale int // A positive value, 2 or higher +} + +func (sf *scaledFont) Close() error { + return sf.font.Close() +} + +func (s *scaledFont) Glyph(dot fixed.Point26_6, r rune) (dr image.Rectangle, _ image.Image, maskp image.Point, advance fixed.Int26_6, ok bool) { + var bmask *bitmapImage + dr, bmask, advance, ok = s.font.glyph(dot, r) + if !ok { + return dr, bmask, maskp, advance, false + } + + d := image.Pt(dot.X.Floor(), dot.Y.Floor()) + dr.Min = dr.Min.Sub(d).Mul(s.scale).Add(d) + dr.Max = dr.Max.Sub(d).Mul(s.scale).Add(d) + advance *= fixed.Int26_6(s.scale) + scaledMask := &scaledImage{ + img: bmask, + scale: s.scale, + bounds: image.Rectangle{ + Min: bmask.bounds.Min.Mul(s.scale * 2), + Max: bmask.bounds.Max.Mul(s.scale * 2), + }, + } + return dr, scaledMask, maskp, advance, true +} + +func (s *scaledFont) GlyphAdvance(r rune) (advance fixed.Int26_6, ok bool) { + advance, ok = s.font.GlyphAdvance(r) + if !ok { + return 0, false + } + advance *= fixed.Int26_6(s.scale) + return advance, true +} + +func (s *scaledFont) GlyphBounds(r rune) (bounds fixed.Rectangle26_6, advance fixed.Int26_6, ok bool) { + bounds, advance, ok = s.font.GlyphBounds(r) + if !ok { + return bounds, advance, false + } + bounds.Min.X *= fixed.Int26_6(s.scale) + bounds.Min.Y *= fixed.Int26_6(s.scale) + bounds.Max.X *= fixed.Int26_6(s.scale) + bounds.Max.Y *= fixed.Int26_6(s.scale) + advance *= fixed.Int26_6(s.scale) + return bounds, advance, true +} + +func (s *scaledFont) Kern(r0, r1 rune) fixed.Int26_6 { + return s.font.Kern(r0, r1) * fixed.Int26_6(s.scale) +} + +func (s *scaledFont) Metrics() font.Metrics { + m := s.font.Metrics() + return font.Metrics{ + Height: m.Height * fixed.Int26_6(s.scale), + Ascent: m.Ascent * fixed.Int26_6(s.scale), + Descent: m.Descent * fixed.Int26_6(s.scale), + } +} + +func euclidianDiv(x, y int) int { + if x < 0 { + x -= y - 1 + } + return x / y +} + +type scaledImage struct { + img *bitmapImage + scale int + bounds image.Rectangle +} + +func (s *scaledImage) ColorModel() color.Model { + return s.img.ColorModel() +} + +func (s *scaledImage) Bounds() image.Rectangle { + return s.bounds +} + +func (s *scaledImage) At(x, y int) color.Color { + x = euclidianDiv(x, s.scale) + y = euclidianDiv(y, s.scale) + return s.img.At(x, y) +} diff --git a/src/contentlock/contentlock.go b/src/contentlock/contentlock.go index c190f8d0..80911218 100644 --- a/src/contentlock/contentlock.go +++ b/src/contentlock/contentlock.go @@ -21,6 +21,7 @@ func GetDefaultData() session.PersistentData { FirstLaunch: true, Settings: session.GameSettings{ LargeDiodes: runtime.GOOS == "anrdoid", + LargerFont: runtime.GOOS == "anrdoid", // Web platforms have XM music set as default. // The same goes for the Androids. diff --git a/src/gamedata/drone_stats.go b/src/gamedata/drone_stats.go index e63b69c2..91e59f07 100644 --- a/src/gamedata/drone_stats.go +++ b/src/gamedata/drone_stats.go @@ -421,7 +421,7 @@ var TruckerAgentStats = InitDroneStats(&AgentStats{ ImpactArea: 15, ProjectileSpeed: 170, Damage: DamageValue{Health: 2, Slow: 1, Morale: 0.2}, - MaxTargets: 5, + MaxTargets: 6, TargetMaxDist: 40, BurstSize: 1, ProjectileRotateSpeed: 24, diff --git a/src/gamedata/version.go b/src/gamedata/version.go index ebe82129..608d66a7 100644 --- a/src/gamedata/version.go +++ b/src/gamedata/version.go @@ -571,6 +571,8 @@ const SeasonNumber = 1 // - Stats & Progress screens now use a larger font // - Add rand drones build button to the lobby // - Add a copyright text to the main menu +// - Large diodes go into a new accessibility options category +// - Added a larger font accessibility option const ( BuildNumber int = 25 BuildMinorNumber int = 0 diff --git a/src/gameui/eui/ebitenui.go b/src/gameui/eui/ebitenui.go index 8d6cd2ed..dd97837d 100644 --- a/src/gameui/eui/ebitenui.go +++ b/src/gameui/eui/ebitenui.go @@ -37,6 +37,10 @@ type Resources struct { Panel *PanelResource DarkPanel *PanelResource + Font1 *font.Face + Font2 *font.Face + Font3 *font.Face + mobile bool } @@ -44,7 +48,6 @@ type TextInputResource struct { Image *widget.TextInputImage Padding widget.Insets TextColors *widget.TextInputColor - FontFace font.Face } type PanelResource struct { @@ -56,7 +59,6 @@ type ButtonResource struct { Image *widget.ButtonImage Padding widget.Insets TextColors *widget.ButtonTextColor - FontFace font.Face } type ToggleButtonResource struct { @@ -65,7 +67,6 @@ type ToggleButtonResource struct { Padding widget.Insets Color color.Color AltColor color.Color - FontFace font.Face } type OptionButtonResource struct { @@ -334,7 +335,7 @@ func NewRecipeView(res *Resources) *RecipeView { iconsContainer.AddChild(icon1) separator := widget.NewText( - widget.TextOpts.Text("", assets.BitmapFont2, res.Button.TextColors.Idle), + widget.TextOpts.Text("", *res.Font2, res.Button.TextColors.Idle), widget.TextOpts.Position(widget.TextPositionCenter, widget.TextPositionCenter), ) iconsContainer.AddChild(separator) @@ -469,7 +470,7 @@ type ButtonConfig struct { func NewSmallButton(res *Resources, scene *ge.Scene, text string, onclick func()) *widget.Button { return NewButtonWithConfig(res, ButtonConfig{ - Font: assets.BitmapFont1, + Font: *res.Font1, Scene: scene, Text: text, OnPressed: onclick, @@ -478,7 +479,7 @@ func NewSmallButton(res *Resources, scene *ge.Scene, text string, onclick func() func NewButton(res *Resources, scene *ge.Scene, text string, onclick func()) *widget.Button { return NewButtonWithConfig(res, ButtonConfig{ - Font: res.Button.FontFace, + Font: *res.Font2, Scene: scene, Text: text, OnPressed: onclick, @@ -488,7 +489,7 @@ func NewButton(res *Resources, scene *ge.Scene, text string, onclick func()) *wi func NewButtonWithConfig(res *Resources, config ButtonConfig) *widget.Button { ff := config.Font if ff == nil { - ff = res.Button.FontFace + ff = *res.Font2 } options := []widget.ButtonOpt{ @@ -674,7 +675,7 @@ func newButtonSelected(res *Resources, text string, opts ...widget.ButtonOpt) *w Stretch: true, })), widget.ButtonOpts.Image(res.ButtonSelected.Image), - widget.ButtonOpts.Text(text, res.ButtonSelected.FontFace, res.ButtonSelected.TextColors), + widget.ButtonOpts.Text(text, *res.Font2, res.ButtonSelected.TextColors), widget.ButtonOpts.TextPadding(res.ButtonSelected.Padding), } options = append(options, opts...) @@ -742,9 +743,9 @@ func NewTextInput(res *Resources, config TextInputConfig, opts ...widget.TextInp widget.TextInputOpts.Image(res.TextInput.Image), widget.TextInputOpts.Color(res.TextInput.TextColors), widget.TextInputOpts.Padding(res.TextInput.Padding), - widget.TextInputOpts.Face(res.TextInput.FontFace), + widget.TextInputOpts.Face(*res.Font1), widget.TextInputOpts.CaretOpts( - widget.CaretOpts.Size(res.TextInput.FontFace, 2), + widget.CaretOpts.Size(*res.Font1, 2), ), widget.TextInputOpts.AllowDuplicateSubmit(true), } @@ -772,10 +773,9 @@ func WidgetRect(w *widget.Widget) gmath.Rect { } } -func LoadResources(device userdevice.Info, loader *resource.Loader) *Resources { - result := &Resources{ - mobile: device.IsMobile(), - } +func LoadResources(dst *Resources, device userdevice.Info, loader *resource.Loader) *Resources { + dst.mobile = device.IsMobile() + result := dst { idle := loader.LoadImage(assets.ImageUITextInputIdle).Data @@ -791,7 +791,6 @@ func LoadResources(device userdevice.Info, loader *resource.Loader) *Resources { Top: 14, Bottom: 10, }, - FontFace: assets.BitmapFont1, TextColors: &widget.TextInputColor{ Idle: NormalTextColor, Disabled: NormalTextColor, @@ -856,7 +855,6 @@ func LoadResources(device userdevice.Info, loader *resource.Loader) *Resources { Padding: buttonPadding, Color: NormalTextColor, AltColor: ge.RGB(0x000000), - FontFace: assets.BitmapFont2, } } @@ -889,7 +887,6 @@ func LoadResources(device userdevice.Info, loader *resource.Loader) *Resources { Padding: buttonPadding, Color: NormalTextColor, AltColor: ge.RGB(0x000000), - FontFace: assets.BitmapFont2, } } @@ -923,7 +920,6 @@ func LoadResources(device userdevice.Info, loader *resource.Loader) *Resources { }, Padding: buttonPadding, TextColors: buttonColors, - FontFace: assets.BitmapFont2, } result.ButtonSelected = &ButtonResource{ Image: &widget.ButtonImage{ @@ -934,7 +930,6 @@ func LoadResources(device userdevice.Info, loader *resource.Loader) *Resources { }, Padding: buttonPadding, TextColors: buttonColors, - FontFace: assets.BitmapFont2, } result.TabButton = &ButtonResource{ Image: &widget.ButtonImage{ @@ -945,7 +940,6 @@ func LoadResources(device userdevice.Info, loader *resource.Loader) *Resources { }, Padding: buttonPadding, TextColors: buttonColors, - FontFace: assets.BitmapFont2, } } diff --git a/src/go.mod b/src/go.mod index 8f180443..72d8ab3a 100644 --- a/src/go.mod +++ b/src/go.mod @@ -7,7 +7,6 @@ replace github.com/ebitenui/ebitenui => github.com/quasilyte/ebitenui v0.0.0-202 require ( github.com/cespare/subcmd v1.1.0 github.com/ebitenui/ebitenui v0.5.6 - github.com/hajimehoshi/bitmapfont/v3 v3.0.0 github.com/hajimehoshi/ebiten/v2 v2.6.7 github.com/hajimehoshi/go-steamworks v0.0.0-20231029064622-d8bdd4105652 github.com/mattn/go-sqlite3 v1.14.22 diff --git a/src/scenes/menus/bootload.go b/src/scenes/menus/bootload.go index c16dc3b1..0897291b 100644 --- a/src/scenes/menus/bootload.go +++ b/src/scenes/menus/bootload.go @@ -34,6 +34,8 @@ func (c *BootloadController) Init(scene *ge.Scene) { d := c.scene.Dict() + c.state.AdjustTextSize(c.state.Persistent.Settings.LargerFont) + if c.state.Persistent.Settings.DebugLogs { scaleFactor := ebiten.DeviceScaleFactor() c.state.Logf("device scale factor: %.2f", scaleFactor) @@ -41,8 +43,8 @@ func (c *BootloadController) Init(scene *ge.Scene) { c.state.Logf("device layout sizes: %vx%v", layoutWidth, layoutHeight) } - smallFont := assets.BitmapFont1 - normalFont := assets.BitmapFont2 + smallFont := c.state.Resources.Font1 + normalFont := c.state.Resources.Font2 root := eui.NewAnchorContainer() rowContainer := eui.NewRowLayoutContainer(10, nil) @@ -153,6 +155,8 @@ func (c *BootloadController) onFirstLaunch() bool { // If it's a Steam Deck, set appropriate defaults. if c.state.Device.IsSteamDeck() { + c.state.Persistent.Settings.LargeDiodes = true + c.state.Persistent.Settings.LargerFont = true c.state.Persistent.Settings.GamepadSettings[0].Layout = int(gameinput.GamepadLayoutSteamDeck) c.state.CombinedInput.SetGamepadLayout(gameinput.GamepadLayoutSteamDeck) c.state.FirstGamepadInput.SetGamepadLayout(gameinput.GamepadLayoutSteamDeck) @@ -229,7 +233,13 @@ func (c *BootloadController) steamSync(ctx *ge.Context, config *assets.Config, p func (c *BootloadController) loadUIResources(ctx *ge.Context, config *assets.Config, progress *float64) { *progress = 0.1 - c.state.Resources.UI = eui.LoadResources(c.state.Device, c.scene.Context().Loader) + uiResources := &eui.Resources{ + Font1: &c.state.Resources.Font1, + Font2: &c.state.Resources.Font2, + Font3: &c.state.Resources.Font3, + } + eui.LoadResources(uiResources, c.state.Device, c.scene.Context().Loader) + c.state.Resources.UI = uiResources } func (c *BootloadController) loadExtra(ctx *ge.Context, config *assets.Config, progress *float64) { diff --git a/src/scenes/menus/controls_gamepad.go b/src/scenes/menus/controls_gamepad.go index f396a9eb..b9975f39 100644 --- a/src/scenes/menus/controls_gamepad.go +++ b/src/scenes/menus/controls_gamepad.go @@ -124,11 +124,12 @@ func (c *ControlsGamepadMenuController) initUI() { var buttons []eui.Widget - smallFont := assets.BitmapFont1 + // TODO: use an adaptive font here as well? (e.g. state.Resources.Font1) + smallFont := assets.Font1 options := &c.state.Persistent.Settings - titleLabel := eui.NewCenteredLabel(d.Get("menu.main.settings")+" -> "+d.Get("menu.options.controls")+" -> "+d.Get("menu.controls.gamepad")+fmt.Sprintf(" %d", c.id+1), assets.BitmapFont3) + titleLabel := eui.NewCenteredLabel(d.Get("menu.main.settings")+" -> "+d.Get("menu.options.controls")+" -> "+d.Get("menu.controls.gamepad")+fmt.Sprintf(" %d", c.id+1), c.state.Resources.Font3) rowContainer.AddChild(titleLabel) panelsPairContainer := eui.NewGridContainer(2, widget.GridLayoutOpts.Spacing(8, 4), diff --git a/src/scenes/menus/controls_keyboardmenu.go b/src/scenes/menus/controls_keyboardmenu.go index 279ca45e..692af521 100644 --- a/src/scenes/menus/controls_keyboardmenu.go +++ b/src/scenes/menus/controls_keyboardmenu.go @@ -46,11 +46,12 @@ func (c *ControlsKeyboardMenuController) initUI() { var buttons []eui.Widget - smallFont := assets.BitmapFont1 + // TODO: use an adaptive font here as well? (e.g. state.Resources.Font1) + smallFont := assets.Font1 options := &c.state.Persistent.Settings - titleLabel := eui.NewCenteredLabel(d.Get("menu.main.settings")+" -> "+d.Get("menu.options.controls")+" -> "+d.Get("menu.controls.keyboard"), assets.BitmapFont3) + titleLabel := eui.NewCenteredLabel(d.Get("menu.main.settings")+" -> "+d.Get("menu.options.controls")+" -> "+d.Get("menu.controls.keyboard"), c.state.Resources.Font3) rowContainer.AddChild(titleLabel) panel := eui.NewTextPanel(uiResources, 0, 0) diff --git a/src/scenes/menus/controls_prompt.go b/src/scenes/menus/controls_prompt.go index 904ad52c..14a1e89f 100644 --- a/src/scenes/menus/controls_prompt.go +++ b/src/scenes/menus/controls_prompt.go @@ -2,7 +2,6 @@ package menus import ( "github.com/quasilyte/ge" - "github.com/quasilyte/roboden-game/assets" "github.com/quasilyte/roboden-game/gameinput" "github.com/quasilyte/roboden-game/gameui/eui" "github.com/quasilyte/roboden-game/session" @@ -37,10 +36,10 @@ func (c *ControlsPromptController) initUI() { d := c.scene.Dict() - titleLabel := eui.NewCenteredLabel(d.Get("game.onboard.welcome"), assets.BitmapFont3) + titleLabel := eui.NewCenteredLabel(d.Get("game.onboard.welcome"), c.state.Resources.Font3) rowContainer.AddChild(titleLabel) - promptText := eui.NewCenteredLabel(d.Get("game.onboard.select_input_method"), assets.BitmapFont1) + promptText := eui.NewCenteredLabel(d.Get("game.onboard.select_input_method"), c.state.Resources.Font1) rowContainer.AddChild(promptText) rowContainer.AddChild(eui.NewButton(uiResources, c.scene, d.Get("menu.controls.keyboard"), func() { diff --git a/src/scenes/menus/controls_touchmenu.go b/src/scenes/menus/controls_touchmenu.go index 2da9493d..39c7a72c 100644 --- a/src/scenes/menus/controls_touchmenu.go +++ b/src/scenes/menus/controls_touchmenu.go @@ -44,9 +44,10 @@ func (c *ControlsTouchMenuController) initUI() { d := c.scene.Dict() - smallFont := assets.BitmapFont1 + // TODO: use an adaptive font here as well? (e.g. state.Resources.Font1) + smallFont := assets.Font1 - titleLabel := eui.NewCenteredLabel(d.Get("menu.main.settings")+" -> "+d.Get("menu.options.controls"), assets.BitmapFont3) + titleLabel := eui.NewCenteredLabel(d.Get("menu.main.settings")+" -> "+d.Get("menu.options.controls"), c.state.Resources.Font3) rowContainer.AddChild(titleLabel) panel := eui.NewTextPanel(uiResources, 0, 0) diff --git a/src/scenes/menus/controlsmenu.go b/src/scenes/menus/controlsmenu.go index 6eb1fa99..a3da3e11 100644 --- a/src/scenes/menus/controlsmenu.go +++ b/src/scenes/menus/controlsmenu.go @@ -2,7 +2,6 @@ package menus import ( "github.com/quasilyte/ge" - "github.com/quasilyte/roboden-game/assets" "github.com/quasilyte/roboden-game/controls" "github.com/quasilyte/roboden-game/gameui/eui" "github.com/quasilyte/roboden-game/session" @@ -45,7 +44,7 @@ func (c *ControlsMenuController) initUI() { var buttons []eui.Widget - titleLabel := eui.NewCenteredLabel(d.Get("menu.main.settings")+" -> "+d.Get("menu.options.controls"), assets.BitmapFont3) + titleLabel := eui.NewCenteredLabel(d.Get("menu.main.settings")+" -> "+d.Get("menu.options.controls"), c.state.Resources.Font3) rowContainer.AddChild(titleLabel) { diff --git a/src/scenes/menus/creditsmenu.go b/src/scenes/menus/creditsmenu.go index b9466671..1841c63f 100644 --- a/src/scenes/menus/creditsmenu.go +++ b/src/scenes/menus/creditsmenu.go @@ -7,7 +7,6 @@ import ( "github.com/quasilyte/ge" "github.com/quasilyte/gmath" - "github.com/quasilyte/roboden-game/assets" "github.com/quasilyte/roboden-game/controls" "github.com/quasilyte/roboden-game/gameui/eui" "github.com/quasilyte/roboden-game/session" @@ -48,9 +47,9 @@ func (c *CreditsMenuController) initUI() { d := c.scene.Context().Dict - smallFont := assets.BitmapFont2 + smallFont := c.state.Resources.Font2 - titleLabel := eui.NewCenteredLabel(d.Get("menu.main.credits"), assets.BitmapFont3) + titleLabel := eui.NewCenteredLabel(d.Get("menu.main.credits"), c.state.Resources.Font3) rowContainer.AddChild(titleLabel) panel := eui.NewTextPanel(uiResources, 640, 92*2) diff --git a/src/scenes/menus/glyphcache_controller.go b/src/scenes/menus/glyphcache_controller.go index 0c72fadf..a469b3ee 100644 --- a/src/scenes/menus/glyphcache_controller.go +++ b/src/scenes/menus/glyphcache_controller.go @@ -6,7 +6,6 @@ import ( "github.com/ebitenui/ebitenui/widget" "github.com/quasilyte/ge" "github.com/quasilyte/gsignal" - "github.com/quasilyte/roboden-game/assets" "github.com/quasilyte/roboden-game/gameui/eui" "github.com/quasilyte/roboden-game/gtask" "github.com/quasilyte/roboden-game/session" @@ -56,7 +55,7 @@ func (c *GlyphCacheController) initUI() { rowContainer := eui.NewRowLayoutContainer(10, nil) root.AddChild(rowContainer) - c.spinner = eui.NewCenteredLabel("--", assets.BitmapFont2) + c.spinner = eui.NewCenteredLabel("--", c.state.Resources.Font2) rowContainer.AddChild(c.spinner) uiObject := eui.NewSceneObject(root) diff --git a/src/scenes/menus/leaderboard_browser.go b/src/scenes/menus/leaderboard_browser.go index d218b5ca..bd8048e6 100644 --- a/src/scenes/menus/leaderboard_browser.go +++ b/src/scenes/menus/leaderboard_browser.go @@ -61,7 +61,7 @@ func (c *LeaderboardBrowserController) initUI() { d := c.scene.Dict() - titleLabel := eui.NewCenteredLabel(d.Get("menu.main.leaderboard")+" -> "+d.Get("menu.leaderboard", c.gameMode), assets.BitmapFont3) + titleLabel := eui.NewCenteredLabel(d.Get("menu.main.leaderboard")+" -> "+d.Get("menu.leaderboard", c.gameMode), c.state.Resources.Font3) rowContainer.AddChild(titleLabel) eui.AddBackground(c.state.BackgroundImage, c.scene) @@ -72,8 +72,8 @@ func (c *LeaderboardBrowserController) initUI() { fetchErr := c.fetchErr d := c.scene.Dict() - smallFont := assets.BitmapFont1 - tinyFont := assets.BitmapFont1 + smallFont := assets.Font1 + tinyFont := assets.Font1 { numSeasons := c.selectedSeason + 1 diff --git a/src/scenes/menus/leaderboard_loading.go b/src/scenes/menus/leaderboard_loading.go index 5a8da839..7c85ac5e 100644 --- a/src/scenes/menus/leaderboard_loading.go +++ b/src/scenes/menus/leaderboard_loading.go @@ -4,7 +4,6 @@ import ( "github.com/ebitenui/ebitenui/widget" "github.com/quasilyte/ge" "github.com/quasilyte/gsignal" - "github.com/quasilyte/roboden-game/assets" "github.com/quasilyte/roboden-game/clientkit" "github.com/quasilyte/roboden-game/gameui/eui" "github.com/quasilyte/roboden-game/gtask" @@ -67,9 +66,9 @@ func (c *LeaderboardLoadingController) initUI() { d := c.scene.Dict() - tinyFont := assets.BitmapFont1 + tinyFont := c.state.Resources.Font1 - titleLabel := eui.NewCenteredLabel(d.Get("menu.main.leaderboard")+" -> "+d.Get("menu.leaderboard", c.gameMode), assets.BitmapFont3) + titleLabel := eui.NewCenteredLabel(d.Get("menu.main.leaderboard")+" -> "+d.Get("menu.leaderboard", c.gameMode), c.state.Resources.Font3) rowContainer.AddChild(titleLabel) c.placeholder = eui.NewCenteredLabel(d.Get("menu.leaderboard.placeholder"), tinyFont) diff --git a/src/scenes/menus/leaderboardmenu.go b/src/scenes/menus/leaderboardmenu.go index 51e98c33..39dfd652 100644 --- a/src/scenes/menus/leaderboardmenu.go +++ b/src/scenes/menus/leaderboardmenu.go @@ -2,7 +2,6 @@ package menus import ( "github.com/quasilyte/ge" - "github.com/quasilyte/roboden-game/assets" "github.com/quasilyte/roboden-game/controls" "github.com/quasilyte/roboden-game/gamedata" "github.com/quasilyte/roboden-game/gameui/eui" @@ -42,7 +41,7 @@ func (c *LeaderboardMenuController) initUI() { d := c.scene.Dict() - titleLabel := eui.NewCenteredLabel(d.Get("menu.main.leaderboard"), assets.BitmapFont3) + titleLabel := eui.NewCenteredLabel(d.Get("menu.main.leaderboard"), c.state.Resources.Font3) rowContainer.AddChild(titleLabel) var buttons = []eui.Widget{ diff --git a/src/scenes/menus/lobbymenu.go b/src/scenes/menus/lobbymenu.go index 12a1a498..8804bcca 100644 --- a/src/scenes/menus/lobbymenu.go +++ b/src/scenes/menus/lobbymenu.go @@ -360,7 +360,7 @@ func (c *LobbyMenuController) createButtonsPanel(uiResources *eui.Resources) *wi d := c.scene.Dict() - tinyFont := assets.BitmapFont1 + tinyFont := assets.Font1 c.difficultyLabel = eui.NewCenteredLabel("Difficulty: 1000%", tinyFont) panel.AddChild(c.difficultyLabel) @@ -470,7 +470,7 @@ func (c *LobbyMenuController) createTabs(uiResources *eui.Resources) *widget.Tab }), widget.TabBookOpts.Tabs(tabs...), widget.TabBookOpts.TabButtonImage(uiResources.TabButton.Image), - widget.TabBookOpts.TabButtonText(uiResources.TabButton.FontFace, uiResources.TabButton.TextColors), + widget.TabBookOpts.TabButtonText(c.state.Resources.Font2, uiResources.TabButton.TextColors), widget.TabBookOpts.TabButtonOpts( widget.ButtonOpts.TextPadding(uiResources.Button.Padding), widget.ButtonOpts.WidgetOpts( @@ -1042,7 +1042,7 @@ func (c *LobbyMenuController) createColonyTab(uiResources *eui.Resources) *widge )), ) - tinyFont := assets.BitmapFont1 + tinyFont := assets.Font1 tab.AddChild(c.createBasesPanel(uiResources)) tab.AddChild(c.createTurretsPanel(uiResources)) @@ -1110,10 +1110,10 @@ func (c *LobbyMenuController) createHelpPanel(uiResources *eui.Resources) *widge panel := eui.NewTextPanel(uiResources, 0, 0) c.helpPanel = panel - tinyFont := assets.BitmapFont1 + tinyFont := c.state.Resources.Font1 label := eui.NewLabel("", tinyFont) - label.MaxWidth = 305 + label.MaxWidth = 300 c.helpLabel = label panel.AddChild(label) @@ -1135,7 +1135,7 @@ func (c *LobbyMenuController) randomSeed() int64 { func (c *LobbyMenuController) createSeedPanel(uiResources *eui.Resources) *widget.Container { worldSettingsPanel := eui.NewPanel(uiResources, 340, 0) - tinyFont := assets.BitmapFont1 + tinyFont := assets.Font1 d := c.scene.Dict() @@ -1328,7 +1328,7 @@ func (c *LobbyMenuController) createTurretsPanel(uiResources *eui.Resources) *wi func (c *LobbyMenuController) createDronesPanel(uiResources *eui.Resources) *widget.Container { dronesPanel := eui.NewPanel(uiResources, 0, 0) - smallFont := assets.BitmapFont1 + smallFont := assets.Font1 grid := widget.NewContainer( widget.ContainerOpts.Layout(widget.NewAnchorLayout()), diff --git a/src/scenes/menus/mainmenu.go b/src/scenes/menus/mainmenu.go index cb8dca2d..5ac2ff54 100644 --- a/src/scenes/menus/mainmenu.go +++ b/src/scenes/menus/mainmenu.go @@ -127,7 +127,7 @@ func (c *MainMenuController) initUI() { buildLabel += " [" + buildinfo.Distribution + "]" } - buildVersionLabel := eui.NewCenteredLabel(buildLabel, assets.BitmapFont1) + buildVersionLabel := eui.NewCenteredLabel(buildLabel, c.state.Resources.Font1) rowContainer.AddChild(buildVersionLabel) setupUI(c.scene, root, c.state.MenuInput, navTree) diff --git a/src/scenes/menus/options_accessibilitymenu.go b/src/scenes/menus/options_accessibilitymenu.go new file mode 100644 index 00000000..b00080b3 --- /dev/null +++ b/src/scenes/menus/options_accessibilitymenu.go @@ -0,0 +1,98 @@ +package menus + +import ( + "github.com/quasilyte/ge" + + "github.com/quasilyte/roboden-game/controls" + "github.com/quasilyte/roboden-game/gameui/eui" + "github.com/quasilyte/roboden-game/session" +) + +type OptionsAccessibilityMenuController struct { + state *session.State + + scene *ge.Scene +} + +func NewOptionsAccessibilityMenuController(state *session.State) *OptionsAccessibilityMenuController { + return &OptionsAccessibilityMenuController{state: state} +} + +func (c *OptionsAccessibilityMenuController) Init(scene *ge.Scene) { + c.scene = scene + c.initUI() +} + +func (c *OptionsAccessibilityMenuController) Update(delta float64) { + c.state.MenuInput.Update() + if c.state.MenuInput.ActionIsJustPressed(controls.ActionMenuBack) { + c.back() + return + } +} + +func (c *OptionsAccessibilityMenuController) initUI() { + eui.AddBackground(c.state.BackgroundImage, c.scene) + uiResources := c.state.Resources.UI + + root := eui.NewAnchorContainer() + rowContainer := eui.NewRowLayoutContainerWithMinWidth(400, 10, nil) + root.AddChild(rowContainer) + + d := c.scene.Dict() + titleLabel := eui.NewCenteredLabel(d.Get("menu.main.settings")+" -> "+d.Get("menu.options.accessibility"), c.state.Resources.Font3) + rowContainer.AddChild(titleLabel) + + options := &c.state.Persistent.Settings + + var buttons []eui.Widget + + largeDiodesSelect := eui.NewSelectButton(eui.SelectButtonConfig{ + PlaySound: true, + Resources: uiResources, + Input: c.state.MenuInput, + BoolValue: &options.LargeDiodes, + Label: d.Get("menu.options.large_diodes"), + ValueNames: []string{ + d.Get("menu.option.off"), + d.Get("menu.option.on"), + }, + }) + c.scene.AddObject(largeDiodesSelect) + rowContainer.AddChild(largeDiodesSelect.Widget) + buttons = append(buttons, largeDiodesSelect.Widget) + + largerFontSelect := eui.NewSelectButton(eui.SelectButtonConfig{ + PlaySound: true, + Resources: uiResources, + Input: c.state.MenuInput, + BoolValue: &options.LargerFont, + Label: d.Get("menu.options.larger_font"), + ValueNames: []string{ + d.Get("menu.option.off"), + d.Get("menu.option.on"), + }, + OnPressed: func() { + c.state.AdjustTextSize(options.LargerFont) + }, + }) + c.scene.AddObject(largerFontSelect) + rowContainer.AddChild(largerFontSelect.Widget) + buttons = append(buttons, largerFontSelect.Widget) + + rowContainer.AddChild(eui.NewTransparentSeparator()) + + backButton := eui.NewButton(uiResources, c.scene, d.Get("menu.back"), func() { + c.back() + }) + rowContainer.AddChild(backButton) + buttons = append(buttons, backButton) + + navTree := createSimpleNavTree(buttons) + setupUI(c.scene, root, c.state.MenuInput, navTree) +} + +func (c *OptionsAccessibilityMenuController) back() { + c.state.SaveGameItem("save.json", c.state.Persistent) + c.scene.Context().ChangeScene(NewOptionsController(c.state)) +} diff --git a/src/scenes/menus/options_extramenu.go b/src/scenes/menus/options_extramenu.go index 028163d7..324f4c65 100644 --- a/src/scenes/menus/options_extramenu.go +++ b/src/scenes/menus/options_extramenu.go @@ -3,7 +3,6 @@ package menus import ( "github.com/quasilyte/ge" - "github.com/quasilyte/roboden-game/assets" "github.com/quasilyte/roboden-game/controls" "github.com/quasilyte/roboden-game/gameui/eui" "github.com/quasilyte/roboden-game/session" @@ -41,7 +40,7 @@ func (c *OptionsExtraMenuController) initUI() { root.AddChild(rowContainer) d := c.scene.Dict() - titleLabel := eui.NewCenteredLabel(d.Get("menu.main.settings")+" -> "+d.Get("menu.options.extra"), assets.BitmapFont3) + titleLabel := eui.NewCenteredLabel(d.Get("menu.main.settings")+" -> "+d.Get("menu.options.extra"), c.state.Resources.Font3) rowContainer.AddChild(titleLabel) options := &c.state.Persistent.Settings @@ -99,21 +98,6 @@ func (c *OptionsExtraMenuController) initUI() { buttons = append(buttons, b.Widget) } - largeDiodesSelect := eui.NewSelectButton(eui.SelectButtonConfig{ - PlaySound: true, - Resources: uiResources, - Input: c.state.MenuInput, - BoolValue: &options.LargeDiodes, - Label: d.Get("menu.options.large_diodes"), - ValueNames: []string{ - d.Get("menu.option.off"), - d.Get("menu.option.on"), - }, - }) - c.scene.AddObject(largeDiodesSelect) - rowContainer.AddChild(largeDiodesSelect.Widget) - buttons = append(buttons, largeDiodesSelect.Widget) - rowContainer.AddChild(eui.NewTransparentSeparator()) terminalButton := eui.NewButton(uiResources, c.scene, d.Get("menu.terminal"), func() { diff --git a/src/scenes/menus/options_gameplaymenu.go b/src/scenes/menus/options_gameplaymenu.go index 920bfa3b..2ef5796a 100644 --- a/src/scenes/menus/options_gameplaymenu.go +++ b/src/scenes/menus/options_gameplaymenu.go @@ -3,7 +3,6 @@ package menus import ( "github.com/quasilyte/ge" - "github.com/quasilyte/roboden-game/assets" "github.com/quasilyte/roboden-game/controls" "github.com/quasilyte/roboden-game/gameui/eui" "github.com/quasilyte/roboden-game/session" @@ -43,7 +42,7 @@ func (c *OptionsGameplayMenuController) initUI() { var buttons []eui.Widget d := c.scene.Dict() - titleLabel := eui.NewCenteredLabel(d.Get("menu.main.settings")+" -> "+d.Get("menu.options.gameplay"), assets.BitmapFont3) + titleLabel := eui.NewCenteredLabel(d.Get("menu.main.settings")+" -> "+d.Get("menu.options.gameplay"), c.state.Resources.Font3) rowContainer.AddChild(titleLabel) options := &c.state.Persistent.Settings diff --git a/src/scenes/menus/options_graphicsmenu.go b/src/scenes/menus/options_graphicsmenu.go index 1dd2214d..ef923a0f 100644 --- a/src/scenes/menus/options_graphicsmenu.go +++ b/src/scenes/menus/options_graphicsmenu.go @@ -50,7 +50,7 @@ func (c *OptionsGraphicsMenuController) initUI() { rowContainer := eui.NewRowLayoutContainerWithMinWidth(520, 10, nil) root.AddChild(rowContainer) - normalFont := assets.BitmapFont3 + normalFont := c.state.Resources.Font3 d := c.scene.Dict() titleLabel := eui.NewCenteredLabel(d.Get("menu.main.settings")+" -> "+d.Get("menu.options.graphics"), normalFont) diff --git a/src/scenes/menus/options_soundmenu.go b/src/scenes/menus/options_soundmenu.go index d034321c..89f12ed0 100644 --- a/src/scenes/menus/options_soundmenu.go +++ b/src/scenes/menus/options_soundmenu.go @@ -43,7 +43,7 @@ func (c *OptionsSoundMenuController) initUI() { root.AddChild(rowContainer) d := c.scene.Dict() - titleLabel := eui.NewCenteredLabel(d.Get("menu.main.settings")+" -> "+d.Get("menu.options.sound"), assets.BitmapFont3) + titleLabel := eui.NewCenteredLabel(d.Get("menu.main.settings")+" -> "+d.Get("menu.options.sound"), c.state.Resources.Font3) rowContainer.AddChild(titleLabel) options := &c.state.Persistent.Settings diff --git a/src/scenes/menus/optionsmenu.go b/src/scenes/menus/optionsmenu.go index 567de2fc..cda77551 100644 --- a/src/scenes/menus/optionsmenu.go +++ b/src/scenes/menus/optionsmenu.go @@ -4,7 +4,6 @@ import ( "github.com/quasilyte/ge" "github.com/quasilyte/ge/xslices" - "github.com/quasilyte/roboden-game/assets" "github.com/quasilyte/roboden-game/controls" "github.com/quasilyte/roboden-game/gameui/eui" "github.com/quasilyte/roboden-game/session" @@ -42,7 +41,7 @@ func (c *OptionsMenuController) initUI() { root.AddChild(rowContainer) d := c.scene.Dict() - titleLabel := eui.NewCenteredLabel(d.Get("menu.main.settings"), assets.BitmapFont3) + titleLabel := eui.NewCenteredLabel(d.Get("menu.main.settings"), c.state.Resources.Font3) rowContainer.AddChild(titleLabel) var buttons []eui.Widget @@ -77,6 +76,14 @@ func (c *OptionsMenuController) initUI() { rowContainer.AddChild(controlsButton) buttons = append(buttons, controlsButton) + if !c.state.Device.IsMobile() { + accessibilityButton := eui.NewButton(uiResources, c.scene, d.Get("menu.options.accessibility"), func() { + c.scene.Context().ChangeScene(NewOptionsAccessibilityMenuController(c.state)) + }) + rowContainer.AddChild(accessibilityButton) + buttons = append(buttons, accessibilityButton) + } + extraButton := eui.NewButton(uiResources, c.scene, d.Get("menu.options.extra"), func() { c.scene.Context().ChangeScene(NewOptionsExtraMenuController(c.state)) }) diff --git a/src/scenes/menus/panic_controller.go b/src/scenes/menus/panic_controller.go index 7237883d..d8e8375e 100644 --- a/src/scenes/menus/panic_controller.go +++ b/src/scenes/menus/panic_controller.go @@ -54,7 +54,7 @@ func (c *PanicController) Init(scene *ge.Scene) { fmt.Println(c.panicInfo.Value) fmt.Println(c.panicInfo.Trace) - errorLabel := ge.NewLabel(assets.BitmapFont1) + errorLabel := ge.NewLabel(assets.Font1) errorLabel.Width = scene.Context().ScreenWidth errorLabel.Height = scene.Context().ScreenHeight errorLabel.GrowVertical = ge.GrowVerticalDown diff --git a/src/scenes/menus/playmenu.go b/src/scenes/menus/playmenu.go index d33c4a0b..c2805ce2 100644 --- a/src/scenes/menus/playmenu.go +++ b/src/scenes/menus/playmenu.go @@ -70,7 +70,7 @@ func (c *PlayMenuController) initUI() { d := c.scene.Dict() - titleLabel := eui.NewCenteredLabel(d.Get("menu.main.play"), assets.BitmapFont3) + titleLabel := eui.NewCenteredLabel(d.Get("menu.main.play"), c.state.Resources.Font3) rowContainer.AddChild(titleLabel) rootGrid := widget.NewContainer( @@ -100,7 +100,7 @@ func (c *PlayMenuController) initUI() { leftPanel.AddChild(buttonsContainer) rootGrid.AddChild(leftPanel) - helpLabel := eui.NewLabel(d.Get("menu.overview.intro_mission"), assets.BitmapFont1) + helpLabel := eui.NewLabel(d.Get("menu.overview.intro_mission"), c.state.Resources.Font1) helpLabel.MaxWidth = 320 c.helpLabel = helpLabel diff --git a/src/scenes/menus/profile_achievementsmenu.go b/src/scenes/menus/profile_achievementsmenu.go index 0fe38723..d71796d6 100644 --- a/src/scenes/menus/profile_achievementsmenu.go +++ b/src/scenes/menus/profile_achievementsmenu.go @@ -9,7 +9,6 @@ import ( "github.com/hajimehoshi/ebiten/v2" "github.com/quasilyte/ge" "github.com/quasilyte/ge/xslices" - "github.com/quasilyte/roboden-game/assets" "github.com/quasilyte/roboden-game/controls" "github.com/quasilyte/roboden-game/gamedata" "github.com/quasilyte/roboden-game/gameui" @@ -62,7 +61,7 @@ func (c *ProfileAchievementsMenuController) initUI() { d := c.scene.Dict() - smallFont := assets.BitmapFont1 + smallFont := c.state.Resources.Font1 helpLabel := eui.NewLabel("", smallFont) helpLabel.MaxWidth = 320 @@ -80,7 +79,7 @@ func (c *ProfileAchievementsMenuController) initUI() { var gridButtonElems []*gameui.NavElem - titleLabel := eui.NewCenteredLabel(d.Get("menu.main.profile")+" -> "+d.Get("menu.profile.achievements"), assets.BitmapFont3) + titleLabel := eui.NewCenteredLabel(d.Get("menu.main.profile")+" -> "+d.Get("menu.profile.achievements"), c.state.Resources.Font3) rowContainer.AddChild(titleLabel) rootGrid := widget.NewContainer( diff --git a/src/scenes/menus/profile_dronecollectionmenu.go b/src/scenes/menus/profile_dronecollectionmenu.go index 010d329e..9c1309b9 100644 --- a/src/scenes/menus/profile_dronecollectionmenu.go +++ b/src/scenes/menus/profile_dronecollectionmenu.go @@ -57,13 +57,13 @@ func (c *ProfileDroneCollectionMenuController) initUI() { d := c.scene.Dict() - tinyFont := assets.BitmapFont1 + tinyFont := c.state.Resources.Font1 helpLabel := eui.NewLabel("", tinyFont) helpLabel.MaxWidth = 340 c.helpLabel = helpLabel - titleLabel := eui.NewCenteredLabel(d.Get("menu.main.profile")+" -> "+d.Get("menu.profile.dronebook"), assets.BitmapFont3) + titleLabel := eui.NewCenteredLabel(d.Get("menu.main.profile")+" -> "+d.Get("menu.profile.dronebook"), c.state.Resources.Font3) rowContainer.AddChild(titleLabel) stats := &c.state.Persistent.PlayerStats @@ -118,7 +118,6 @@ func (c *ProfileDroneCollectionMenuController) initUI() { for i := range drones { drone := drones[i] available := droneIsUnlocked(drone) - available = true frame := droneImage(drone, available) b := eui.NewItemButton(uiResources, frame, tinyFont, "", 0, func() {}) b.Button.CursorEnteredEvent.AddHandler(func(args interface{}) { diff --git a/src/scenes/menus/profile_progressmenu.go b/src/scenes/menus/profile_progressmenu.go index d403e22d..5a894cb1 100644 --- a/src/scenes/menus/profile_progressmenu.go +++ b/src/scenes/menus/profile_progressmenu.go @@ -5,7 +5,6 @@ import ( "github.com/ebitenui/ebitenui/widget" "github.com/quasilyte/ge" - "github.com/quasilyte/roboden-game/assets" "github.com/quasilyte/roboden-game/controls" "github.com/quasilyte/roboden-game/gamedata" "github.com/quasilyte/roboden-game/gameui/eui" @@ -45,7 +44,7 @@ func (c *ProfileProgressMenuController) initUI() { d := c.scene.Dict() - titleLabel := eui.NewCenteredLabel(d.Get("menu.main.profile")+" -> "+d.Get("menu.profile.progress"), assets.BitmapFont3) + titleLabel := eui.NewCenteredLabel(d.Get("menu.main.profile")+" -> "+d.Get("menu.profile.progress"), c.state.Resources.Font3) rowContainer.AddChild(titleLabel) panel := eui.NewTextPanel(uiResources, 0, 0) @@ -55,7 +54,7 @@ func (c *ProfileProgressMenuController) initUI() { stats := c.state.Persistent.PlayerStats - smallFont := assets.BitmapFont2 + smallFont := c.state.Resources.Font2 grid := eui.NewGridContainer(2, widget.GridLayoutOpts.Spacing(24, 4), widget.GridLayoutOpts.Stretch([]bool{true, false}, nil)) diff --git a/src/scenes/menus/profile_statsmenu.go b/src/scenes/menus/profile_statsmenu.go index 7dd736d3..0c6d967d 100644 --- a/src/scenes/menus/profile_statsmenu.go +++ b/src/scenes/menus/profile_statsmenu.go @@ -5,7 +5,6 @@ import ( "github.com/ebitenui/ebitenui/widget" "github.com/quasilyte/ge" - "github.com/quasilyte/roboden-game/assets" "github.com/quasilyte/roboden-game/controls" "github.com/quasilyte/roboden-game/gamedata" "github.com/quasilyte/roboden-game/gameui/eui" @@ -47,13 +46,13 @@ func (c *ProfileStatsMenuController) initUI() { d := c.scene.Dict() - titleLabel := eui.NewCenteredLabel(d.Get("menu.main.profile")+" -> "+d.Get("menu.profile.stats"), assets.BitmapFont3) + titleLabel := eui.NewCenteredLabel(d.Get("menu.main.profile")+" -> "+d.Get("menu.profile.stats"), c.state.Resources.Font3) rowContainer.AddChild(titleLabel) panel := eui.NewTextPanel(uiResources, 0, 0) rowContainer.AddChild(panel) - smallFont := assets.BitmapFont2 + smallFont := c.state.Resources.Font2 stats := c.state.Persistent.PlayerStats grid := eui.NewGridContainer(2, widget.GridLayoutOpts.Spacing(24, 4), diff --git a/src/scenes/menus/profilemenu.go b/src/scenes/menus/profilemenu.go index 00b7e262..86c850ec 100644 --- a/src/scenes/menus/profilemenu.go +++ b/src/scenes/menus/profilemenu.go @@ -2,7 +2,6 @@ package menus import ( "github.com/quasilyte/ge" - "github.com/quasilyte/roboden-game/assets" "github.com/quasilyte/roboden-game/controls" "github.com/quasilyte/roboden-game/gameui/eui" "github.com/quasilyte/roboden-game/session" @@ -41,7 +40,7 @@ func (c *ProfileMenuController) initUI() { d := c.scene.Dict() - titleLabel := eui.NewCenteredLabel(d.Get("menu.main.profile"), assets.BitmapFont3) + titleLabel := eui.NewCenteredLabel(d.Get("menu.main.profile"), c.state.Resources.Font3) rowContainer.AddChild(titleLabel) buttons := []eui.Widget{ diff --git a/src/scenes/menus/replaymenu.go b/src/scenes/menus/replaymenu.go index 7020fecc..1adf39b5 100644 --- a/src/scenes/menus/replaymenu.go +++ b/src/scenes/menus/replaymenu.go @@ -51,7 +51,7 @@ func (c *ReplayMenuController) initUI() { d := c.scene.Dict() - smallFont := assets.BitmapFont1 + smallFont := assets.Font1 helpLabel := eui.NewLabel("", smallFont) helpLabel.MaxWidth = 268 @@ -70,7 +70,7 @@ func (c *ReplayMenuController) initUI() { bottomNavBlock.NewElem(backButton) - titleLabel := eui.NewCenteredLabel(d.Get("menu.main.profile")+" -> "+d.Get("menu.profile.watch_replay"), assets.BitmapFont3) + titleLabel := eui.NewCenteredLabel(d.Get("menu.main.profile")+" -> "+d.Get("menu.profile.watch_replay"), c.state.Resources.Font3) rowContainer.AddChild(titleLabel) rootGrid := widget.NewContainer( diff --git a/src/scenes/menus/schemamenu.go b/src/scenes/menus/schemamenu.go index 43671649..41ba0360 100644 --- a/src/scenes/menus/schemamenu.go +++ b/src/scenes/menus/schemamenu.go @@ -6,7 +6,6 @@ import ( "github.com/ebitenui/ebitenui/widget" "github.com/quasilyte/ge" "github.com/quasilyte/gmath" - "github.com/quasilyte/roboden-game/assets" "github.com/quasilyte/roboden-game/controls" "github.com/quasilyte/roboden-game/descriptions" "github.com/quasilyte/roboden-game/gamedata" @@ -84,13 +83,13 @@ func (c *SchemaMenuController) initUI() { d := c.scene.Dict() - smallFont := assets.BitmapFont1 + smallFont := c.state.Resources.Font1 helpLabel := eui.NewLabel("", smallFont) helpLabel.MaxWidth = 268 c.helpLabel = helpLabel - titleLabel := eui.NewCenteredLabel(d.Get("menu.main.schema"), assets.BitmapFont3) + titleLabel := eui.NewCenteredLabel(d.Get("menu.main.schema"), c.state.Resources.Font3) rowContainer.AddChild(titleLabel) numSlots := 10 diff --git a/src/scenes/menus/schemanamemenu.go b/src/scenes/menus/schemanamemenu.go index dd8341fc..84d3c1b5 100644 --- a/src/scenes/menus/schemanamemenu.go +++ b/src/scenes/menus/schemanamemenu.go @@ -83,7 +83,7 @@ func (c *SchemaNameMenu) initUI() { return } - titleLabel := eui.NewCenteredLabel(d.Get("menu.schema_name"), assets.BitmapFont3) + titleLabel := eui.NewCenteredLabel(d.Get("menu.schema_name"), c.state.Resources.Font3) rowContainer.AddChild(titleLabel) textinput := eui.NewTextInput(uiResources, eui.TextInputConfig{SteamDeck: c.state.Device.IsSteamDeck()}, diff --git a/src/scenes/menus/secretmenu.go b/src/scenes/menus/secretmenu.go index 5b4ba5dc..b9f98b2f 100644 --- a/src/scenes/menus/secretmenu.go +++ b/src/scenes/menus/secretmenu.go @@ -44,9 +44,9 @@ func (c *SecretMenuController) initUI() { d := c.scene.Context().Dict - smallFont := assets.BitmapFont1 + smallFont := assets.Font1 - titleLabel := eui.NewCenteredLabel("???", assets.BitmapFont3) + titleLabel := eui.NewCenteredLabel("???", c.state.Resources.Font3) rowContainer.AddChild(titleLabel) panel := eui.NewTextPanel(uiResources, 0, 0) diff --git a/src/scenes/menus/splashscreen.go b/src/scenes/menus/splashscreen.go index 22773201..e4b48782 100644 --- a/src/scenes/menus/splashscreen.go +++ b/src/scenes/menus/splashscreen.go @@ -97,7 +97,7 @@ func (c *SplashScreenController) Init(scene *ge.Scene) { d := scene.Dict() input := c.state.MenuInput - presskeyLabelShade := ge.NewLabel(assets.BitmapFont2) + presskeyLabelShade := ge.NewLabel(c.state.Resources.Font2) presskeyLabelShade.Width = scene.Context().WindowWidth presskeyLabelShade.AlignHorizontal = ge.AlignHorizontalCenter presskeyLabelShade.Text = input.ReplaceKeyNames(d.Get("game.splash.presskey", input.DetectInputMode())) @@ -106,7 +106,7 @@ func (c *SplashScreenController) Init(scene *ge.Scene) { scene.AddGraphics(presskeyLabelShade) { - presskeyLabel := ge.NewLabel(assets.BitmapFont2) + presskeyLabel := ge.NewLabel(c.state.Resources.Font2) presskeyLabel.Width = presskeyLabelShade.Width presskeyLabel.AlignHorizontal = presskeyLabelShade.AlignHorizontal presskeyLabel.Text = presskeyLabelShade.Text diff --git a/src/scenes/menus/submit_screen.go b/src/scenes/menus/submit_screen.go index 9de57a64..b9a2842e 100644 --- a/src/scenes/menus/submit_screen.go +++ b/src/scenes/menus/submit_screen.go @@ -4,7 +4,6 @@ import ( "github.com/ebitenui/ebitenui/widget" "github.com/quasilyte/ge" "github.com/quasilyte/gsignal" - "github.com/quasilyte/roboden-game/assets" "github.com/quasilyte/roboden-game/clientkit" "github.com/quasilyte/roboden-game/gamedata" "github.com/quasilyte/roboden-game/gameui/eui" @@ -73,9 +72,9 @@ func (c *submitScreenController) initUI() { rowContainer := eui.NewRowLayoutContainer(10, nil) root.AddChild(rowContainer) - rowContainer.AddChild(eui.NewCenteredLabel(d.Get("menu.submit.title"), assets.BitmapFont3)) + rowContainer.AddChild(eui.NewCenteredLabel(d.Get("menu.submit.title"), c.state.Resources.Font3)) - c.spinner = eui.NewCenteredLabel("--", assets.BitmapFont2) + c.spinner = eui.NewCenteredLabel("--", c.state.Resources.Font2) rowContainer.AddChild(c.spinner) uiObject := eui.NewSceneObject(root) diff --git a/src/scenes/menus/terminalmenu.go b/src/scenes/menus/terminalmenu.go index 9d7a80a3..86c3c008 100644 --- a/src/scenes/menus/terminalmenu.go +++ b/src/scenes/menus/terminalmenu.go @@ -89,9 +89,9 @@ func (c *TerminalMenu) initUI() { var widgets []eui.Widget - tinyFont := assets.BitmapFont1 + tinyFont := assets.Font1 - titleLabel := eui.NewCenteredLabel(d.Get("menu.main.settings")+" -> "+d.Get("menu.options.extra")+" -> "+d.Get("menu.terminal"), assets.BitmapFont3) + titleLabel := eui.NewCenteredLabel(d.Get("menu.main.settings")+" -> "+d.Get("menu.options.extra")+" -> "+d.Get("menu.terminal"), c.state.Resources.Font3) rowContainer.AddChild(titleLabel) outputPanel := eui.NewTextPanel(uiResources, 520, 200) diff --git a/src/scenes/menus/usernamemenu.go b/src/scenes/menus/usernamemenu.go index ef9c4121..0f9780fb 100644 --- a/src/scenes/menus/usernamemenu.go +++ b/src/scenes/menus/usernamemenu.go @@ -61,9 +61,9 @@ func (c *UserNameMenu) initUI() { d := c.scene.Dict() - smallFont := assets.BitmapFont1 + smallFont := assets.Font1 - titleLabel := eui.NewCenteredLabel(d.Get("menu.user_name"), assets.BitmapFont3) + titleLabel := eui.NewCenteredLabel(d.Get("menu.user_name"), c.state.Resources.Font3) rowContainer.AddChild(titleLabel) var widgets []eui.Widget diff --git a/src/scenes/staging/arena_manager.go b/src/scenes/staging/arena_manager.go index 0e7379b8..a584fef4 100644 --- a/src/scenes/staging/arena_manager.go +++ b/src/scenes/staging/arena_manager.go @@ -261,7 +261,7 @@ func (m *arenaManager) spawnGrenadiers() { func (m *arenaManager) createWaveInfoMessageNode() *messageNode { s := m.createWaveInfoText() - message := newScreenTutorialHintNode(m.world.cameras[0], gmath.Vec{X: 16, Y: 70}, gmath.Vec{}, s) + message := newScreenTutorialHintNode(m.world.cameras[0], gmath.Vec{X: 16, Y: 70}, gmath.Vec{}, s, m.world.textFontFace) message.xpadding = 20 return message } diff --git a/src/scenes/staging/debug_drone_label_node.go b/src/scenes/staging/debug_drone_label_node.go index 7f1c9d16..f60e9f38 100644 --- a/src/scenes/staging/debug_drone_label_node.go +++ b/src/scenes/staging/debug_drone_label_node.go @@ -37,7 +37,7 @@ func (l *debugDroneLabelNode) Init(scene *ge.Scene) { l.dispose() }) - l.label = ge.NewLabel(assets.BitmapFont1) + l.label = ge.NewLabel(assets.Font1) l.label.Pos.Base = &l.drone.pos l.label.Width = 32 l.label.Height = 24 diff --git a/src/scenes/staging/message_manager.go b/src/scenes/staging/message_manager.go index 1140e45e..a2d43474 100644 --- a/src/scenes/staging/message_manager.go +++ b/src/scenes/staging/message_manager.go @@ -73,9 +73,9 @@ func (m *messageManager) SetMainMessage(info queuedMessageInfo) { messagePos := gmath.Vec{X: 16, Y: 70} worldPos := info.forceWorldPos || info.targetPos.Base != nil if worldPos { - m.mainMessage = newWorldTutorialHintNode(m.cam, messagePos, info.targetPos, info.text) + m.mainMessage = newWorldTutorialHintNode(m.cam, messagePos, info.targetPos, info.text, m.world.textFontFace) } else { - m.mainMessage = newScreenTutorialHintNode(m.cam, messagePos, info.targetPos.Offset, info.text) + m.mainMessage = newScreenTutorialHintNode(m.cam, messagePos, info.targetPos.Offset, info.text, m.world.textFontFace) } m.world.rootScene.AddObject(m.mainMessage) } @@ -106,11 +106,14 @@ func (m *messageManager) nextMessage() { m.messageTimer = 0 m.messageTimeLimit = info.timer messagePos := gmath.Vec{X: 16, Y: 202} + if m.world.largerFont { + messagePos.Y += 12 + } worldPos := info.forceWorldPos || info.targetPos.Base != nil if worldPos { - m.message = newWorldTutorialHintNode(m.cam, messagePos, info.targetPos, info.text) + m.message = newWorldTutorialHintNode(m.cam, messagePos, info.targetPos, info.text, m.world.textFontFace) } else { - m.message = newScreenTutorialHintNode(m.cam, messagePos, info.targetPos.Offset, info.text) + m.message = newScreenTutorialHintNode(m.cam, messagePos, info.targetPos.Offset, info.text, m.world.textFontFace) } m.message.trackedObject = info.trackedObject m.world.rootScene.AddObject(m.message) diff --git a/src/scenes/staging/message_node.go b/src/scenes/staging/message_node.go index bd8255bf..a429297a 100644 --- a/src/scenes/staging/message_node.go +++ b/src/scenes/staging/message_node.go @@ -4,8 +4,8 @@ import ( "github.com/hajimehoshi/ebiten/v2/text" "github.com/quasilyte/ge" "github.com/quasilyte/gmath" - "github.com/quasilyte/roboden-game/assets" "github.com/quasilyte/roboden-game/viewport" + "golang.org/x/image/font" ) type messageNode struct { @@ -15,6 +15,8 @@ type messageNode struct { targetLine2 *ge.Line camera *viewport.Camera + ff font.Face + highlightRect *ge.Rect highlightStep float64 highlightValue float64 @@ -32,29 +34,31 @@ type messageNode struct { xpadding float64 } -func estimateMessageBounds(s string, xpadding float64) (width, height float64) { - bounds := text.BoundString(assets.BitmapFont1, s) +func estimateMessageBounds(s string, xpadding float64, ff font.Face) (width, height float64) { + bounds := text.BoundString(ff, s) width = (float64(bounds.Dx()) + 16) + xpadding height = (float64(bounds.Dy()) + 16) return width, height } -func newScreenTutorialHintNode(camera *viewport.Camera, pos, targetPos gmath.Vec, text string) *messageNode { +func newScreenTutorialHintNode(camera *viewport.Camera, pos, targetPos gmath.Vec, text string, ff font.Face) *messageNode { return &messageNode{ pos: pos, targetPos: ge.Pos{Offset: targetPos}, text: text, camera: camera, screenPos: true, + ff: ff, } } -func newWorldTutorialHintNode(camera *viewport.Camera, pos gmath.Vec, targetPos ge.Pos, text string) *messageNode { +func newWorldTutorialHintNode(camera *viewport.Camera, pos gmath.Vec, targetPos ge.Pos, text string, ff font.Face) *messageNode { return &messageNode{ pos: pos, targetPos: targetPos, text: text, camera: camera, + ff: ff, } } @@ -73,7 +77,7 @@ func (m *messageNode) ContainsPos(pos gmath.Vec) bool { } func (m *messageNode) Init(scene *ge.Scene) { - m.width, m.height = estimateMessageBounds(m.text, m.xpadding) + m.width, m.height = estimateMessageBounds(m.text, m.xpadding, m.ff) m.rect = ge.NewRect(scene.Context(), m.width, m.height) m.rect.OutlineColorScale.SetColor(ge.RGB(0x5e5a5d)) @@ -90,7 +94,7 @@ func (m *messageNode) Init(scene *ge.Scene) { m.highlightRect.Pos.Offset = m.pos.Sub(gmath.Vec{X: 1, Y: 1}) m.highlightRect.Visible = false - m.label = ge.NewLabel(assets.BitmapFont1) + m.label = ge.NewLabel(m.ff) m.label.AlignHorizontal = ge.AlignHorizontalCenter m.label.AlignVertical = ge.AlignVerticalCenter m.label.Width = m.width diff --git a/src/scenes/staging/results_controller.go b/src/scenes/staging/results_controller.go index b67095c0..9c147eb9 100644 --- a/src/scenes/staging/results_controller.go +++ b/src/scenes/staging/results_controller.go @@ -10,7 +10,6 @@ import ( "github.com/ebitenui/ebitenui/widget" "github.com/quasilyte/ge" "github.com/quasilyte/ge/xslices" - "github.com/quasilyte/roboden-game/assets" "github.com/quasilyte/roboden-game/buildinfo" "github.com/quasilyte/roboden-game/contentlock" "github.com/quasilyte/roboden-game/controls" @@ -414,7 +413,7 @@ func (c *resultsController) initUI() { rowContainer := eui.NewRowLayoutContainerWithMinWidth(320, 10, nil) root.AddChild(rowContainer) - smallFont := assets.BitmapFont1 + smallFont := c.state.Resources.Font1 d := c.scene.Dict() @@ -425,7 +424,7 @@ func (c *resultsController) initUI() { titleString += "!" } - titleLabel := eui.NewCenteredLabel(titleString, assets.BitmapFont3) + titleLabel := eui.NewCenteredLabel(titleString, c.state.Resources.Font3) rowContainer.AddChild(titleLabel) panel := eui.NewTextPanel(uiResources, 0, 0) diff --git a/src/scenes/staging/rewards_controller.go b/src/scenes/staging/rewards_controller.go index 455d991e..b2e0fb19 100644 --- a/src/scenes/staging/rewards_controller.go +++ b/src/scenes/staging/rewards_controller.go @@ -86,7 +86,7 @@ func (c *rewardsController) Update(delta float64) { explosionSound := resource.AudioID(int(assets.AudioExplosion1) + explosionSoundIndex) c.scene.Audio().PlaySound(explosionSound) - smallFont := assets.BitmapFont2 + smallFont := c.state.Resources.Font2 pair := c.lines[0] c.lines = c.lines[1:] c.grid.AddChild(eui.NewLabel(pair[0], smallFont)) @@ -116,7 +116,7 @@ func (c *rewardsController) initUI() { d := c.scene.Dict() - rowContainer.AddChild(eui.NewCenteredLabel(d.Get("menu.results.rewards"), assets.BitmapFont3)) + rowContainer.AddChild(eui.NewCenteredLabel(d.Get("menu.results.rewards"), c.state.Resources.Font3)) panel := eui.NewTextPanel(uiResources, 580, 0) c.panel = panel diff --git a/src/scenes/staging/staging_controller.go b/src/scenes/staging/staging_controller.go index f4da77ff..4bc27e40 100644 --- a/src/scenes/staging/staging_controller.go +++ b/src/scenes/staging/staging_controller.go @@ -433,6 +433,8 @@ func (c *Controller) doInit(scene *ge.Scene) { world.inputMode = c.state.GetInput(0).DetectInputMode() world.creepCoordinator = newCreepCoordinator(world) world.bfs = pathing.NewGreedyBFS(world.pathgrid.Size()) + world.textFontFace = c.state.Resources.Font1 + world.largerFont = c.state.Persistent.Settings.LargerFont c.world = world world.Init() @@ -610,7 +612,7 @@ func (c *Controller) doInit(scene *ge.Scene) { if c.state.Persistent.Settings.ShowFPS || c.state.Persistent.Settings.ShowTimer { if len(c.world.cameras) != 0 { - c.debugInfo = ge.NewLabel(assets.BitmapFont1) + c.debugInfo = ge.NewLabel(assets.Font1) c.debugInfo.SetColorScaleRGBA(0x9d, 0xd7, 0x93, 0xff) c.debugInfo.Pos.Offset = gmath.Vec{X: 10, Y: 20} c.world.cameras[0].UI.AddGraphics(c.debugInfo) @@ -957,7 +959,7 @@ func (c *Controller) onExitButtonClicked() { cam.UI.Visible = true c.nodeRunner.SetPaused(true) msg := cam.input.ReplaceKeyNames(d.Get("game.exit.notice", input.DetectInputMode())) - exitNotice := newScreenTutorialHintNode(cam.Camera, gmath.Vec{}, gmath.Vec{}, msg) + exitNotice := newScreenTutorialHintNode(cam.Camera, gmath.Vec{}, gmath.Vec{}, msg, c.world.textFontFace) c.exitNotices = append(c.exitNotices, exitNotice) c.nodeRunner.exitPrompt = true c.scene.AddObject(exitNotice) @@ -1750,7 +1752,7 @@ func (c *Controller) onPausePressed() { d := c.scene.Dict() cam.UI.Visible = true msg := cam.input.ReplaceKeyNames(d.Get("game.pause.notice", input.DetectInputMode())) - pauseNotice := newScreenTutorialHintNode(cam.Camera, gmath.Vec{}, gmath.Vec{}, msg) + pauseNotice := newScreenTutorialHintNode(cam.Camera, gmath.Vec{}, gmath.Vec{}, msg, c.world.textFontFace) c.pauseNotices = append(c.pauseNotices, pauseNotice) c.scene.AddObject(pauseNotice) noticeSize := gmath.Vec{X: pauseNotice.width, Y: pauseNotice.height} diff --git a/src/scenes/staging/tooltip_manager.go b/src/scenes/staging/tooltip_manager.go index dc0dec34..11b2e2f5 100644 --- a/src/scenes/staging/tooltip_manager.go +++ b/src/scenes/staging/tooltip_manager.go @@ -313,7 +313,7 @@ func (m *tooltipManager) createTooltip(pos gmath.Vec, s string) { camera := m.player.state.camera.Camera messagePos := pos.Sub(camera.ScreenPos) - w, h := estimateMessageBounds(s, 0) + w, h := estimateMessageBounds(s, 0, m.world.textFontFace) if w+messagePos.X+16 > camera.Rect.Max.X { messagePos.X -= w } @@ -323,6 +323,6 @@ func (m *tooltipManager) createTooltip(pos gmath.Vec, s string) { messagePos.Y += 16 } - m.message = newScreenTutorialHintNode(camera, messagePos, gmath.Vec{}, s) + m.message = newScreenTutorialHintNode(camera, messagePos, gmath.Vec{}, s, m.world.textFontFace) m.scene.AddObject(m.message) } diff --git a/src/scenes/staging/tutorial_manager.go b/src/scenes/staging/tutorial_manager.go index e1bbbb45..504422a8 100644 --- a/src/scenes/staging/tutorial_manager.go +++ b/src/scenes/staging/tutorial_manager.go @@ -408,7 +408,7 @@ func (m *tutorialManager) maybeCompleteStep() bool { case 23: var creeps []arenaWaveUnit - for i := 0; i < 6; i++ { + for i := 0; i < 7; i++ { super := i == 0 creeps = append(creeps, arenaWaveUnit{stats: gamedata.WandererCreepStats, super: super}) } diff --git a/src/scenes/staging/world_state.go b/src/scenes/staging/world_state.go index 163dcf36..60e00b81 100644 --- a/src/scenes/staging/world_state.go +++ b/src/scenes/staging/world_state.go @@ -16,12 +16,16 @@ import ( "github.com/quasilyte/roboden-game/session" "github.com/quasilyte/roboden-game/userdevice" "github.com/quasilyte/roboden-game/viewport" + "golang.org/x/image/font" ) type worldState struct { rand *gmath.Rand localRand *gmath.Rand + textFontFace font.Face + largerFont bool + sessionState *session.State rootScene *ge.Scene diff --git a/src/session/state.go b/src/session/state.go index eb51d111..9880f746 100644 --- a/src/session/state.go +++ b/src/session/state.go @@ -13,6 +13,7 @@ import ( "github.com/quasilyte/ge" "github.com/quasilyte/ge/langs" "github.com/quasilyte/ge/xslices" + "golang.org/x/image/font" "github.com/quasilyte/roboden-game/assets" "github.com/quasilyte/roboden-game/gamedata" @@ -192,6 +193,10 @@ type Achievement struct { type Resources struct { UI *eui.Resources + + Font1 font.Face + Font2 font.Face + Font3 font.Face } type GamepadSettings struct { @@ -212,6 +217,7 @@ type GameSettings struct { ShowFPS bool ShowTimer bool LargeDiodes bool + LargerFont bool DebugLogs bool DebugDroneLabels bool Demo bool @@ -278,6 +284,16 @@ func (state *State) AdjustVolumeLevels() { assets.VolumeMultiplier(state.Persistent.Settings.EffectsVolumeLevel)) } +func (state *State) AdjustTextSize(larger bool) { + if larger { + state.Resources.Font1 = assets.Font1_3 + } else { + state.Resources.Font1 = assets.Font1 + } + state.Resources.Font2 = assets.Font2 + state.Resources.Font3 = assets.Font3 +} + func (state *State) ReloadInputs() { state.BoundInputs[0] = state.resolveInputMethod(gameinput.PlayerInputMethod(state.Persistent.Settings.Player1InputMethod)) state.BoundInputs[1] = state.resolveInputMethod(gameinput.PlayerInputMethod(state.Persistent.Settings.Player2InputMethod)) @@ -361,10 +377,10 @@ func (state *State) CacheCommonGlyphs() { return } - alphabet := "0123456789 <>.,=+-:()[]&@'\"%!?●◌|\\" - text.CacheGlyphs(assets.BitmapFont1, alphabet) - text.CacheGlyphs(assets.BitmapFont2, alphabet) - text.CacheGlyphs(assets.BitmapFont3, alphabet) + alphabet := "0123456789<>.,=+-:()[]&@'\"%!?●◌|\\ ~" + text.CacheGlyphs(state.Resources.Font1, alphabet) + text.CacheGlyphs(state.Resources.Font2, alphabet) + text.CacheGlyphs(state.Resources.Font3, alphabet) } func (state *State) CacheGlyphs() { @@ -376,9 +392,9 @@ func (state *State) CacheGlyphs() { if state.Persistent.Settings.Lang == "ru" { alphabet = "абвгдеёжзийклмнопрстуфхцчшщъыьэюяАБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯabxyABXYRL" } - text.CacheGlyphs(assets.BitmapFont1, alphabet) - text.CacheGlyphs(assets.BitmapFont2, alphabet) - text.CacheGlyphs(assets.BitmapFont3, alphabet) + text.CacheGlyphs(state.Resources.Font1, alphabet) + text.CacheGlyphs(state.Resources.Font2, alphabet) + text.CacheGlyphs(state.Resources.Font3, alphabet) } func (state *State) FindNextReplayIndex() int {