Compare commits
18 Commits
9b7abc7725
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 0ddb6c85e1 | |||
| f84007902e | |||
| 49ae2ae41f | |||
| c701421a8f | |||
| 1ecb427106 | |||
| c87779cc09 | |||
| 24594fa89a | |||
| 030779794e | |||
| 495c23a3d2 | |||
| 911ee7a13e | |||
| b876ccbb09 | |||
| 94684e8758 | |||
| 0c116665bc | |||
| d0ed49d192 | |||
| 5e013a8414 | |||
| 0cdbeb768d | |||
| cd0477cc4c | |||
| c6e2779429 |
@@ -50,6 +50,9 @@ set(APP_SOURCES
|
||||
source/core/rendering/text.cpp
|
||||
source/core/rendering/texture.cpp
|
||||
|
||||
# Core - Locale
|
||||
source/core/locale/locale.cpp
|
||||
|
||||
# Core - Resources
|
||||
source/core/resources/resource_list.cpp
|
||||
source/core/resources/resource_cache.cpp
|
||||
|
||||
@@ -7,23 +7,23 @@ assets:
|
||||
- type: BITMAP
|
||||
path: ${PREFIX}/data/font/smb2.gif
|
||||
- type: FONT
|
||||
path: ${PREFIX}/data/font/smb2.txt
|
||||
path: ${PREFIX}/data/font/smb2.fnt
|
||||
- type: BITMAP
|
||||
path: ${PREFIX}/data/font/aseprite.gif
|
||||
- type: FONT
|
||||
path: ${PREFIX}/data/font/aseprite.txt
|
||||
path: ${PREFIX}/data/font/aseprite.fnt
|
||||
- type: BITMAP
|
||||
path: ${PREFIX}/data/font/gauntlet.gif
|
||||
- type: FONT
|
||||
path: ${PREFIX}/data/font/gauntlet.txt
|
||||
path: ${PREFIX}/data/font/gauntlet.fnt
|
||||
- type: BITMAP
|
||||
path: ${PREFIX}/data/font/subatomic.gif
|
||||
- type: FONT
|
||||
path: ${PREFIX}/data/font/subatomic.txt
|
||||
path: ${PREFIX}/data/font/subatomic.fnt
|
||||
- type: BITMAP
|
||||
path: ${PREFIX}/data/font/8bithud.gif
|
||||
- type: FONT
|
||||
path: ${PREFIX}/data/font/8bithud.txt
|
||||
path: ${PREFIX}/data/font/8bithud.fnt
|
||||
|
||||
# PALETTES
|
||||
palettes:
|
||||
@@ -56,6 +56,13 @@ assets:
|
||||
- type: PALETTE
|
||||
path: ${PREFIX}/data/palette/steam-lords.pal
|
||||
|
||||
# LOCALE
|
||||
locale:
|
||||
- type: DATA
|
||||
path: ${PREFIX}/data/locale/en.yaml
|
||||
- type: DATA
|
||||
path: ${PREFIX}/data/locale/ca.yaml
|
||||
|
||||
# INPUT
|
||||
input:
|
||||
- type: DATA
|
||||
|
||||
132
data/font/8bithud.fnt
Normal file
@@ -0,0 +1,132 @@
|
||||
# Font: 8bithud — generado desde 8-bit-hud.ttf size 5
|
||||
# Generado con tools/font_gen/font_gen.py
|
||||
|
||||
box_width 8
|
||||
box_height 8
|
||||
columns 15
|
||||
|
||||
# codepoint_decimal ancho_visual
|
||||
32 3 # U+0020
|
||||
33 2 # !
|
||||
34 5 # "
|
||||
35 6 # #
|
||||
36 6 # $
|
||||
37 6 # %
|
||||
38 6 # &
|
||||
39 2 # '
|
||||
40 3 # (
|
||||
41 3 # )
|
||||
42 4 # *
|
||||
43 3 # +
|
||||
44 2 # ,
|
||||
45 3 # -
|
||||
46 2 # .
|
||||
47 4 # /
|
||||
48 6 # 0
|
||||
49 3 # 1
|
||||
50 6 # 2
|
||||
51 6 # 3
|
||||
52 6 # 4
|
||||
53 6 # 5
|
||||
54 6 # 6
|
||||
55 6 # 7
|
||||
56 6 # 8
|
||||
57 6 # 9
|
||||
58 2 # :
|
||||
59 2 # ;
|
||||
60 4 # <
|
||||
61 3 # =
|
||||
62 4 # >
|
||||
63 6 # ?
|
||||
64 8 # @
|
||||
65 6 # A
|
||||
66 6 # B
|
||||
67 6 # C
|
||||
68 6 # D
|
||||
69 6 # E
|
||||
70 6 # F
|
||||
71 6 # G
|
||||
72 6 # H
|
||||
73 6 # I
|
||||
74 6 # J
|
||||
75 6 # K
|
||||
76 6 # L
|
||||
77 6 # M
|
||||
78 6 # N
|
||||
79 6 # O
|
||||
80 6 # P
|
||||
81 6 # Q
|
||||
82 6 # R
|
||||
83 6 # S
|
||||
84 6 # T
|
||||
85 6 # U
|
||||
86 5 # V
|
||||
87 6 # W
|
||||
88 6 # X
|
||||
89 6 # Y
|
||||
90 6 # Z
|
||||
91 3 # [
|
||||
92 4 # \
|
||||
93 3 # ]
|
||||
94 4 # ^
|
||||
95 6 # _
|
||||
96 2 # `
|
||||
97 5 # a
|
||||
98 5 # b
|
||||
99 5 # c
|
||||
100 5 # d
|
||||
101 5 # e
|
||||
102 5 # f
|
||||
103 5 # g
|
||||
104 5 # h
|
||||
105 4 # i
|
||||
106 5 # j
|
||||
107 5 # k
|
||||
108 5 # l
|
||||
109 6 # m
|
||||
110 5 # n
|
||||
111 5 # o
|
||||
112 5 # p
|
||||
113 5 # q
|
||||
114 5 # r
|
||||
115 5 # s
|
||||
116 4 # t
|
||||
117 5 # u
|
||||
118 5 # v
|
||||
119 6 # w
|
||||
120 4 # x
|
||||
121 4 # y
|
||||
122 5 # z
|
||||
123 4 # {
|
||||
124 1 # |
|
||||
125 4 # }
|
||||
126 4 # ~
|
||||
192 6 # À
|
||||
193 6 # Á
|
||||
200 6 # È
|
||||
201 6 # É
|
||||
205 6 # Í
|
||||
207 6 # Ï
|
||||
210 6 # Ò
|
||||
211 6 # Ó
|
||||
218 6 # Ú
|
||||
220 6 # Ü
|
||||
209 6 # Ñ
|
||||
199 6 # Ç
|
||||
224 5 # à
|
||||
225 5 # á
|
||||
232 5 # è
|
||||
233 5 # é
|
||||
237 4 # í
|
||||
239 4 # ï
|
||||
242 5 # ò
|
||||
243 5 # ó
|
||||
250 5 # ú
|
||||
252 5 # ü
|
||||
241 5 # ñ
|
||||
231 5 # ç
|
||||
161 2 # ¡
|
||||
191 6 # ¿
|
||||
171 4 # «
|
||||
187 4 # »
|
||||
183 2 # ·
|
||||
|
Before Width: | Height: | Size: 680 B After Width: | Height: | Size: 837 B |
@@ -1,194 +0,0 @@
|
||||
# box width
|
||||
8
|
||||
# box height
|
||||
8
|
||||
# 32 espacio ( )
|
||||
2
|
||||
# 33 !
|
||||
2
|
||||
# 34 "
|
||||
5
|
||||
# 35 #
|
||||
6
|
||||
# 36 $
|
||||
6
|
||||
# 37 %
|
||||
6
|
||||
# 38 &
|
||||
6
|
||||
# 39 '
|
||||
2
|
||||
# 40 (
|
||||
3
|
||||
# 41 )
|
||||
3
|
||||
# 42 *
|
||||
4
|
||||
# 43 +
|
||||
3
|
||||
# 44 ,
|
||||
2
|
||||
# 45 -
|
||||
3
|
||||
# 46 .
|
||||
2
|
||||
# 47 /
|
||||
4
|
||||
# 48 0
|
||||
6
|
||||
# 49 1
|
||||
6
|
||||
# 50 2
|
||||
6
|
||||
# 51 3
|
||||
6
|
||||
# 52 4
|
||||
6
|
||||
# 53 5
|
||||
6
|
||||
# 54 6
|
||||
6
|
||||
# 55 7
|
||||
6
|
||||
# 56 8
|
||||
6
|
||||
# 57 9
|
||||
6
|
||||
# 58 :
|
||||
2
|
||||
# 59 ;
|
||||
2
|
||||
# 60 <
|
||||
4
|
||||
# 61 =
|
||||
3
|
||||
# 62 >
|
||||
4
|
||||
# 63 ?
|
||||
6
|
||||
# 64 @
|
||||
8
|
||||
# 65 A
|
||||
6
|
||||
# 66 B
|
||||
6
|
||||
# 67 C
|
||||
6
|
||||
# 68 D
|
||||
6
|
||||
# 69 E
|
||||
6
|
||||
# 70 F
|
||||
6
|
||||
# 71 G
|
||||
6
|
||||
# 72 H
|
||||
6
|
||||
# 73 I
|
||||
6
|
||||
# 74 J
|
||||
6
|
||||
# 75 K
|
||||
6
|
||||
# 76 L
|
||||
6
|
||||
# 77 M
|
||||
6
|
||||
# 78 N
|
||||
6
|
||||
# 79 O
|
||||
6
|
||||
# 80 P
|
||||
6
|
||||
# 81 Q
|
||||
6
|
||||
# 82 R
|
||||
6
|
||||
# 83 S
|
||||
6
|
||||
# 84 T
|
||||
6
|
||||
# 85 U
|
||||
6
|
||||
# 86 V
|
||||
5
|
||||
# 87 W
|
||||
6
|
||||
# 88 X
|
||||
6
|
||||
# 89 Y
|
||||
6
|
||||
# 90 Z
|
||||
6
|
||||
# 91 [
|
||||
3
|
||||
# 92 \
|
||||
5
|
||||
# 93 ]
|
||||
3
|
||||
# 94 ^
|
||||
4
|
||||
# 95 _
|
||||
6
|
||||
# 96 `
|
||||
2
|
||||
# 97 a
|
||||
5
|
||||
# 98 b
|
||||
5
|
||||
# 99 c
|
||||
5
|
||||
# 100 d
|
||||
5
|
||||
# 101 e
|
||||
5
|
||||
# 102 f
|
||||
5
|
||||
# 103 g
|
||||
5
|
||||
# 104 h
|
||||
5
|
||||
# 105 i
|
||||
4
|
||||
# 106 j
|
||||
5
|
||||
# 107 k
|
||||
5
|
||||
# 108 l
|
||||
5
|
||||
# 109 m
|
||||
6
|
||||
# 110 n
|
||||
5
|
||||
# 111 o
|
||||
5
|
||||
# 112 p
|
||||
5
|
||||
# 113 q
|
||||
5
|
||||
# 114 r
|
||||
5
|
||||
# 115 s
|
||||
5
|
||||
# 116 t
|
||||
4
|
||||
# 117 u
|
||||
5
|
||||
# 118 v
|
||||
5
|
||||
# 119 w
|
||||
6
|
||||
# 120 x
|
||||
4
|
||||
# 121 y
|
||||
4
|
||||
# 122 z
|
||||
5
|
||||
# 123 {
|
||||
3
|
||||
# 124 |
|
||||
2
|
||||
# 125 }
|
||||
3
|
||||
# 126 ~
|
||||
3
|
||||
134
data/font/aseprite.fnt
Normal file
@@ -0,0 +1,134 @@
|
||||
# Font: aseprite — generado desde aseprite_font.gif
|
||||
# Generado con tools/font_gen/font_gen.py
|
||||
|
||||
box_width 10
|
||||
box_height 7
|
||||
columns 16
|
||||
cell_spacing 1
|
||||
row_spacing 4
|
||||
|
||||
# codepoint_decimal ancho_visual
|
||||
32 3 # U+0020
|
||||
33 1 # !
|
||||
34 3 # "
|
||||
35 5 # #
|
||||
36 4 # $
|
||||
37 5 # %
|
||||
38 5 # &
|
||||
39 2 # '
|
||||
40 2 # (
|
||||
41 2 # )
|
||||
42 5 # *
|
||||
43 5 # +
|
||||
44 2 # ,
|
||||
45 3 # -
|
||||
46 1 # .
|
||||
47 3 # /
|
||||
48 4 # 0
|
||||
49 2 # 1
|
||||
50 4 # 2
|
||||
51 4 # 3
|
||||
52 4 # 4
|
||||
53 4 # 5
|
||||
54 4 # 6
|
||||
55 4 # 7
|
||||
56 4 # 8
|
||||
57 4 # 9
|
||||
58 1 # :
|
||||
59 2 # ;
|
||||
60 3 # <
|
||||
61 4 # =
|
||||
62 3 # >
|
||||
63 4 # ?
|
||||
64 8 # @
|
||||
65 4 # A
|
||||
66 4 # B
|
||||
67 4 # C
|
||||
68 4 # D
|
||||
69 4 # E
|
||||
70 4 # F
|
||||
71 4 # G
|
||||
72 4 # H
|
||||
73 1 # I
|
||||
74 2 # J
|
||||
75 4 # K
|
||||
76 4 # L
|
||||
77 5 # M
|
||||
78 4 # N
|
||||
79 5 # O
|
||||
80 4 # P
|
||||
81 5 # Q
|
||||
82 4 # R
|
||||
83 4 # S
|
||||
84 5 # T
|
||||
85 4 # U
|
||||
86 5 # V
|
||||
87 7 # W
|
||||
88 5 # X
|
||||
89 5 # Y
|
||||
90 4 # Z
|
||||
91 2 # [
|
||||
92 3 # \
|
||||
93 2 # ]
|
||||
94 5 # ^
|
||||
95 5 # _
|
||||
96 3 # `
|
||||
97 4 # a
|
||||
98 4 # b
|
||||
99 4 # c
|
||||
100 4 # d
|
||||
101 4 # e
|
||||
102 2 # f
|
||||
103 4 # g
|
||||
104 4 # h
|
||||
105 1 # i
|
||||
106 2 # j
|
||||
107 4 # k
|
||||
108 1 # l
|
||||
109 7 # m
|
||||
110 4 # n
|
||||
111 4 # o
|
||||
112 4 # p
|
||||
113 4 # q
|
||||
114 3 # r
|
||||
115 3 # s
|
||||
116 2 # t
|
||||
117 4 # u
|
||||
118 4 # v
|
||||
119 5 # w
|
||||
120 5 # x
|
||||
121 4 # y
|
||||
122 4 # z
|
||||
123 3 # {
|
||||
124 1 # |
|
||||
125 3 # }
|
||||
126 4 # ~
|
||||
192 5 # À
|
||||
193 5 # Á
|
||||
200 5 # È
|
||||
201 5 # É
|
||||
205 5 # Í
|
||||
207 5 # Ï
|
||||
210 5 # Ò
|
||||
211 5 # Ó
|
||||
218 5 # Ú
|
||||
220 5 # Ü
|
||||
209 5 # Ñ
|
||||
199 5 # Ç
|
||||
224 5 # à
|
||||
225 5 # á
|
||||
232 5 # è
|
||||
233 5 # é
|
||||
237 5 # í
|
||||
239 5 # ï
|
||||
242 5 # ò
|
||||
243 5 # ó
|
||||
250 5 # ú
|
||||
252 5 # ü
|
||||
241 5 # ñ
|
||||
231 5 # ç
|
||||
161 5 # ¡
|
||||
191 5 # ¿
|
||||
171 5 # «
|
||||
187 5 # »
|
||||
183 5 # ·
|
||||
|
Before Width: | Height: | Size: 640 B After Width: | Height: | Size: 3.9 KiB |
@@ -1,194 +0,0 @@
|
||||
# box width
|
||||
8
|
||||
# box height
|
||||
8
|
||||
# 32 espacio ( )
|
||||
3
|
||||
# 33 !
|
||||
1
|
||||
# 34 "
|
||||
3
|
||||
# 35 #
|
||||
3
|
||||
# 36 $
|
||||
4
|
||||
# 37 %
|
||||
5
|
||||
# 38 &
|
||||
5
|
||||
# 39 '
|
||||
2
|
||||
# 40 (
|
||||
2
|
||||
# 41 )
|
||||
2
|
||||
# 42 *
|
||||
5
|
||||
# 43 +
|
||||
5
|
||||
# 44 ,
|
||||
3
|
||||
# 45 -
|
||||
3
|
||||
# 46 .
|
||||
1
|
||||
# 47 /
|
||||
4
|
||||
# 48 0
|
||||
4
|
||||
# 49 1
|
||||
2
|
||||
# 50 2
|
||||
4
|
||||
# 51 3
|
||||
4
|
||||
# 52 4
|
||||
4
|
||||
# 53 5
|
||||
4
|
||||
# 54 6
|
||||
4
|
||||
# 55 7
|
||||
4
|
||||
# 56 8
|
||||
4
|
||||
# 57 9
|
||||
4
|
||||
# 58 :
|
||||
1
|
||||
# 59 ;
|
||||
1
|
||||
# 60 <
|
||||
3
|
||||
# 61 =
|
||||
4
|
||||
# 62 >
|
||||
4
|
||||
# 63 ?
|
||||
4
|
||||
# 64 @
|
||||
7
|
||||
# 65 A
|
||||
4
|
||||
# 66 B
|
||||
4
|
||||
# 67 C
|
||||
4
|
||||
# 68 D
|
||||
4
|
||||
# 69 E
|
||||
4
|
||||
# 70 F
|
||||
4
|
||||
# 71 G
|
||||
4
|
||||
# 72 H
|
||||
4
|
||||
# 73 I
|
||||
2
|
||||
# 74 J
|
||||
2
|
||||
# 75 K
|
||||
4
|
||||
# 76 L
|
||||
4
|
||||
# 77 M
|
||||
5
|
||||
# 78 N
|
||||
4
|
||||
# 79 O
|
||||
5
|
||||
# 80 P
|
||||
4
|
||||
# 81 Q
|
||||
5
|
||||
# 82 R
|
||||
4
|
||||
# 83 S
|
||||
4
|
||||
# 84 T
|
||||
5
|
||||
# 85 U
|
||||
4
|
||||
# 86 V
|
||||
5
|
||||
# 87 W
|
||||
7
|
||||
# 88 X
|
||||
5
|
||||
# 89 Y
|
||||
5
|
||||
# 90 Z
|
||||
4
|
||||
# 91 [
|
||||
2
|
||||
# 92 \
|
||||
3
|
||||
# 93 ]
|
||||
2
|
||||
# 94 ^
|
||||
5
|
||||
# 95 _
|
||||
5
|
||||
# 96 `
|
||||
3
|
||||
# 97 a
|
||||
4
|
||||
# 98 b
|
||||
4
|
||||
# 99 c
|
||||
4
|
||||
# 100 d
|
||||
4
|
||||
# 101 e
|
||||
4
|
||||
# 102 f
|
||||
2
|
||||
# 103 g
|
||||
4
|
||||
# 104 h
|
||||
4
|
||||
# 105 i
|
||||
1
|
||||
# 106 j
|
||||
2
|
||||
# 107 k
|
||||
4
|
||||
# 108 l
|
||||
1
|
||||
# 109 m
|
||||
7
|
||||
# 110 n
|
||||
4
|
||||
# 111 o
|
||||
4
|
||||
# 112 p
|
||||
4
|
||||
# 113 q
|
||||
4
|
||||
# 114 r
|
||||
3
|
||||
# 115 s
|
||||
3
|
||||
# 116 t
|
||||
2
|
||||
# 117 u
|
||||
4
|
||||
# 118 v
|
||||
4
|
||||
# 119 w
|
||||
5
|
||||
# 120 x
|
||||
5
|
||||
# 121 y
|
||||
4
|
||||
# 122 z
|
||||
4
|
||||
# 123 {
|
||||
3
|
||||
# 124 |
|
||||
3
|
||||
# 125 }
|
||||
3
|
||||
# 126 ~
|
||||
5
|
||||
128
data/font/gauntlet.fnt
Normal file
@@ -0,0 +1,128 @@
|
||||
# Font: gauntlet — generado desde Gauntlet.ttf size 7
|
||||
# Generado con tools/font_gen/font_gen.py
|
||||
|
||||
box_width 8
|
||||
box_height 8
|
||||
columns 15
|
||||
|
||||
# codepoint_decimal ancho_visual
|
||||
32 3 # U+0020
|
||||
33 2 # !
|
||||
34 5 # "
|
||||
35 6 # #
|
||||
36 6 # $
|
||||
37 7 # %
|
||||
38 7 # &
|
||||
39 2 # '
|
||||
40 4 # (
|
||||
41 4 # )
|
||||
42 6 # *
|
||||
43 8 # +
|
||||
44 2 # ,
|
||||
45 7 # -
|
||||
46 2 # .
|
||||
47 7 # /
|
||||
48 7 # 0
|
||||
49 6 # 1
|
||||
50 6 # 2
|
||||
51 6 # 3
|
||||
52 7 # 4
|
||||
53 6 # 5
|
||||
54 6 # 6
|
||||
55 6 # 7
|
||||
56 6 # 8
|
||||
57 6 # 9
|
||||
58 2 # :
|
||||
59 3 # ;
|
||||
60 5 # <
|
||||
61 6 # =
|
||||
62 5 # >
|
||||
63 6 # ?
|
||||
64 6 # @
|
||||
65 6 # A
|
||||
66 7 # B
|
||||
67 7 # C
|
||||
68 7 # D
|
||||
69 7 # E
|
||||
70 7 # F
|
||||
71 7 # G
|
||||
72 6 # H
|
||||
73 6 # I
|
||||
74 7 # J
|
||||
75 7 # K
|
||||
76 7 # L
|
||||
77 7 # M
|
||||
78 7 # N
|
||||
79 7 # O
|
||||
80 7 # P
|
||||
81 7 # Q
|
||||
82 7 # R
|
||||
83 6 # S
|
||||
84 6 # T
|
||||
85 6 # U
|
||||
86 6 # V
|
||||
87 7 # W
|
||||
88 7 # X
|
||||
89 6 # Y
|
||||
90 7 # Z
|
||||
91 8 # [
|
||||
92 3 # \
|
||||
93 7 # ]
|
||||
94 7 # ^
|
||||
95 8 # _
|
||||
97 6 # a
|
||||
98 7 # b
|
||||
99 7 # c
|
||||
100 7 # d
|
||||
101 7 # e
|
||||
102 7 # f
|
||||
103 7 # g
|
||||
104 6 # h
|
||||
105 6 # i
|
||||
106 7 # j
|
||||
107 7 # k
|
||||
108 7 # l
|
||||
109 7 # m
|
||||
110 7 # n
|
||||
111 7 # o
|
||||
112 7 # p
|
||||
113 7 # q
|
||||
114 7 # r
|
||||
115 6 # s
|
||||
116 6 # t
|
||||
117 6 # u
|
||||
118 6 # v
|
||||
119 7 # w
|
||||
120 7 # x
|
||||
121 6 # y
|
||||
122 7 # z
|
||||
126 6 # ~
|
||||
192 6 # À
|
||||
193 6 # Á
|
||||
200 7 # È
|
||||
201 7 # É
|
||||
205 6 # Í
|
||||
207 6 # Ï
|
||||
210 7 # Ò
|
||||
211 7 # Ó
|
||||
218 6 # Ú
|
||||
220 6 # Ü
|
||||
209 7 # Ñ
|
||||
199 7 # Ç
|
||||
224 6 # à
|
||||
225 6 # á
|
||||
232 7 # è
|
||||
233 7 # é
|
||||
237 6 # í
|
||||
239 6 # ï
|
||||
242 7 # ò
|
||||
243 7 # ó
|
||||
250 6 # ú
|
||||
252 6 # ü
|
||||
241 7 # ñ
|
||||
231 7 # ç
|
||||
161 2 # ¡
|
||||
191 6 # ¿
|
||||
171 5 # «
|
||||
187 5 # »
|
||||
183 2 # ·
|
||||
|
Before Width: | Height: | Size: 810 B After Width: | Height: | Size: 959 B |
@@ -1,194 +0,0 @@
|
||||
# box width
|
||||
8
|
||||
# box height
|
||||
8
|
||||
# 32 espacio ( )
|
||||
6
|
||||
# 33 !
|
||||
2
|
||||
# 34 "
|
||||
5
|
||||
# 35 #
|
||||
6
|
||||
# 36 $
|
||||
6
|
||||
# 37 %
|
||||
7
|
||||
# 38 &
|
||||
7
|
||||
# 39 '
|
||||
2
|
||||
# 40 (
|
||||
4
|
||||
# 41 )
|
||||
4
|
||||
# 42 *
|
||||
6
|
||||
# 43 +
|
||||
8
|
||||
# 44 ,
|
||||
2
|
||||
# 45 -
|
||||
7
|
||||
# 46 .
|
||||
2
|
||||
# 47 /
|
||||
7
|
||||
# 48 0
|
||||
7
|
||||
# 49 1
|
||||
6
|
||||
# 50 2
|
||||
6
|
||||
# 51 3
|
||||
6
|
||||
# 52 4
|
||||
7
|
||||
# 53 5
|
||||
6
|
||||
# 54 6
|
||||
6
|
||||
# 55 7
|
||||
6
|
||||
# 56 8
|
||||
6
|
||||
# 57 9
|
||||
6
|
||||
# 58 :
|
||||
2
|
||||
# 59 ;
|
||||
2
|
||||
# 60 <
|
||||
5
|
||||
# 61 =
|
||||
6
|
||||
# 62 >
|
||||
5
|
||||
# 63 ?
|
||||
6
|
||||
# 64 @
|
||||
6
|
||||
# 65 A
|
||||
6
|
||||
# 66 B
|
||||
7
|
||||
# 67 C
|
||||
7
|
||||
# 68 D
|
||||
7
|
||||
# 69 E
|
||||
7
|
||||
# 70 F
|
||||
7
|
||||
# 71 G
|
||||
7
|
||||
# 72 H
|
||||
6
|
||||
# 73 I
|
||||
6
|
||||
# 74 J
|
||||
7
|
||||
# 75 K
|
||||
7
|
||||
# 76 L
|
||||
7
|
||||
# 77 M
|
||||
7
|
||||
# 78 N
|
||||
7
|
||||
# 79 O
|
||||
7
|
||||
# 80 P
|
||||
7
|
||||
# 81 Q
|
||||
7
|
||||
# 82 R
|
||||
7
|
||||
# 83 S
|
||||
6
|
||||
# 84 T
|
||||
6
|
||||
# 85 U
|
||||
6
|
||||
# 86 V
|
||||
6
|
||||
# 87 W
|
||||
7
|
||||
# 88 X
|
||||
7
|
||||
# 89 Y
|
||||
6
|
||||
# 90 Z
|
||||
7
|
||||
# 91 [
|
||||
8
|
||||
# 92 \
|
||||
3
|
||||
# 93 ]
|
||||
7
|
||||
# 94 ^
|
||||
7
|
||||
# 95 _
|
||||
8
|
||||
# 96 `
|
||||
0
|
||||
# 97 a
|
||||
6
|
||||
# 98 b
|
||||
7
|
||||
# 99 c
|
||||
7
|
||||
# 100 d
|
||||
7
|
||||
# 101 e
|
||||
7
|
||||
# 102 f
|
||||
7
|
||||
# 103 g
|
||||
7
|
||||
# 104 h
|
||||
6
|
||||
# 105 i
|
||||
6
|
||||
# 106 j
|
||||
7
|
||||
# 107 k
|
||||
7
|
||||
# 108 l
|
||||
7
|
||||
# 109 m
|
||||
7
|
||||
# 110 n
|
||||
7
|
||||
# 111 o
|
||||
7
|
||||
# 112 p
|
||||
7
|
||||
# 113 q
|
||||
7
|
||||
# 114 r
|
||||
7
|
||||
# 115 s
|
||||
6
|
||||
# 116 t
|
||||
6
|
||||
# 117 u
|
||||
6
|
||||
# 118 v
|
||||
6
|
||||
# 119 w
|
||||
7
|
||||
# 120 x
|
||||
7
|
||||
# 121 y
|
||||
6
|
||||
# 122 z
|
||||
7
|
||||
# 123 {
|
||||
0
|
||||
# 124 |
|
||||
0
|
||||
# 125 }
|
||||
0
|
||||
# 126 ~
|
||||
0
|
||||
132
data/font/smb2.fnt
Normal file
@@ -0,0 +1,132 @@
|
||||
# Font: smb2 — generado desde Super Mario Bros. 2.ttf size 8
|
||||
# Generado con tools/font_gen/font_gen.py
|
||||
|
||||
box_width 8
|
||||
box_height 8
|
||||
columns 15
|
||||
|
||||
# codepoint_decimal ancho_visual
|
||||
32 7 # U+0020
|
||||
33 7 # !
|
||||
34 7 # "
|
||||
35 7 # #
|
||||
36 7 # $
|
||||
37 7 # %
|
||||
38 7 # &
|
||||
39 7 # '
|
||||
40 7 # (
|
||||
41 7 # )
|
||||
42 7 # *
|
||||
43 7 # +
|
||||
44 7 # ,
|
||||
45 7 # -
|
||||
46 7 # .
|
||||
47 7 # /
|
||||
48 7 # 0
|
||||
49 7 # 1
|
||||
50 7 # 2
|
||||
51 7 # 3
|
||||
52 7 # 4
|
||||
53 7 # 5
|
||||
54 7 # 6
|
||||
55 7 # 7
|
||||
56 7 # 8
|
||||
57 7 # 9
|
||||
58 7 # :
|
||||
59 7 # ;
|
||||
60 7 # <
|
||||
61 7 # =
|
||||
62 7 # >
|
||||
63 7 # ?
|
||||
64 7 # @
|
||||
65 7 # A
|
||||
66 7 # B
|
||||
67 7 # C
|
||||
68 7 # D
|
||||
69 7 # E
|
||||
70 7 # F
|
||||
71 7 # G
|
||||
72 7 # H
|
||||
73 7 # I
|
||||
74 7 # J
|
||||
75 7 # K
|
||||
76 7 # L
|
||||
77 7 # M
|
||||
78 7 # N
|
||||
79 7 # O
|
||||
80 7 # P
|
||||
81 7 # Q
|
||||
82 7 # R
|
||||
83 7 # S
|
||||
84 7 # T
|
||||
85 7 # U
|
||||
86 7 # V
|
||||
87 7 # W
|
||||
88 7 # X
|
||||
89 7 # Y
|
||||
90 7 # Z
|
||||
91 7 # [
|
||||
92 7 # \
|
||||
93 7 # ]
|
||||
94 7 # ^
|
||||
95 7 # _
|
||||
96 7 # `
|
||||
97 7 # a
|
||||
98 7 # b
|
||||
99 7 # c
|
||||
100 7 # d
|
||||
101 7 # e
|
||||
102 7 # f
|
||||
103 7 # g
|
||||
104 7 # h
|
||||
105 7 # i
|
||||
106 7 # j
|
||||
107 7 # k
|
||||
108 7 # l
|
||||
109 7 # m
|
||||
110 7 # n
|
||||
111 7 # o
|
||||
112 7 # p
|
||||
113 7 # q
|
||||
114 7 # r
|
||||
115 7 # s
|
||||
116 7 # t
|
||||
117 7 # u
|
||||
118 7 # v
|
||||
119 7 # w
|
||||
120 7 # x
|
||||
121 7 # y
|
||||
122 7 # z
|
||||
123 7 # {
|
||||
124 7 # |
|
||||
125 7 # }
|
||||
126 7 # ~
|
||||
192 7 # À
|
||||
193 7 # Á
|
||||
200 7 # È
|
||||
201 7 # É
|
||||
205 7 # Í
|
||||
207 7 # Ï
|
||||
210 7 # Ò
|
||||
211 7 # Ó
|
||||
218 7 # Ú
|
||||
220 7 # Ü
|
||||
209 7 # Ñ
|
||||
199 7 # Ç
|
||||
224 7 # à
|
||||
225 7 # á
|
||||
232 7 # è
|
||||
233 7 # é
|
||||
237 7 # í
|
||||
239 7 # ï
|
||||
242 7 # ò
|
||||
243 7 # ó
|
||||
250 7 # ú
|
||||
252 7 # ü
|
||||
241 7 # ñ
|
||||
231 7 # ç
|
||||
161 7 # ¡
|
||||
191 7 # ¿
|
||||
171 7 # «
|
||||
187 7 # »
|
||||
183 7 # ·
|
||||
|
Before Width: | Height: | Size: 798 B After Width: | Height: | Size: 968 B |
@@ -1,194 +0,0 @@
|
||||
# box width
|
||||
8
|
||||
# box height
|
||||
8
|
||||
# 32 espacio ( )
|
||||
7
|
||||
# 33 !
|
||||
7
|
||||
# 34 "
|
||||
7
|
||||
# 35 #
|
||||
7
|
||||
# 36 $
|
||||
7
|
||||
# 37 %
|
||||
7
|
||||
# 38 &
|
||||
7
|
||||
# 39 '
|
||||
7
|
||||
# 40 (
|
||||
7
|
||||
# 41 )
|
||||
7
|
||||
# 42 *
|
||||
7
|
||||
# 43 +
|
||||
7
|
||||
# 44 ,
|
||||
7
|
||||
# 45 -
|
||||
7
|
||||
# 46 .
|
||||
7
|
||||
# 47 /
|
||||
7
|
||||
# 48 0
|
||||
7
|
||||
# 49 1
|
||||
7
|
||||
# 50 2
|
||||
7
|
||||
# 51 3
|
||||
7
|
||||
# 52 4
|
||||
7
|
||||
# 53 5
|
||||
7
|
||||
# 54 6
|
||||
7
|
||||
# 55 7
|
||||
7
|
||||
# 56 8
|
||||
7
|
||||
# 57 9
|
||||
7
|
||||
# 58 :
|
||||
7
|
||||
# 59 ;
|
||||
7
|
||||
# 60 <
|
||||
7
|
||||
# 61 =
|
||||
7
|
||||
# 62 >
|
||||
7
|
||||
# 63 ?
|
||||
7
|
||||
# 64 @
|
||||
7
|
||||
# 65 A
|
||||
7
|
||||
# 66 B
|
||||
7
|
||||
# 67 C
|
||||
7
|
||||
# 68 D
|
||||
7
|
||||
# 69 E
|
||||
7
|
||||
# 70 F
|
||||
7
|
||||
# 71 G
|
||||
7
|
||||
# 72 H
|
||||
7
|
||||
# 73 I
|
||||
7
|
||||
# 74 J
|
||||
7
|
||||
# 75 K
|
||||
7
|
||||
# 76 L
|
||||
7
|
||||
# 77 M
|
||||
7
|
||||
# 78 N
|
||||
7
|
||||
# 79 O
|
||||
7
|
||||
# 80 P
|
||||
7
|
||||
# 81 Q
|
||||
7
|
||||
# 82 R
|
||||
7
|
||||
# 83 S
|
||||
7
|
||||
# 84 T
|
||||
7
|
||||
# 85 U
|
||||
7
|
||||
# 86 V
|
||||
7
|
||||
# 87 W
|
||||
7
|
||||
# 88 X
|
||||
7
|
||||
# 89 Y
|
||||
7
|
||||
# 90 Z
|
||||
7
|
||||
# 91 [
|
||||
7
|
||||
# 92 \
|
||||
7
|
||||
# 93 ]
|
||||
7
|
||||
# 94 ^
|
||||
7
|
||||
# 95 _
|
||||
7
|
||||
# 96 `
|
||||
7
|
||||
# 97 a
|
||||
7
|
||||
# 98 b
|
||||
7
|
||||
# 99 c
|
||||
7
|
||||
# 100 d
|
||||
7
|
||||
# 101 e
|
||||
7
|
||||
# 102 f
|
||||
7
|
||||
# 103 g
|
||||
7
|
||||
# 104 h
|
||||
7
|
||||
# 105 i
|
||||
7
|
||||
# 106 j
|
||||
7
|
||||
# 107 k
|
||||
7
|
||||
# 108 l
|
||||
7
|
||||
# 109 m
|
||||
7
|
||||
# 110 n
|
||||
7
|
||||
# 111 o
|
||||
7
|
||||
# 112 p
|
||||
7
|
||||
# 113 q
|
||||
7
|
||||
# 114 r
|
||||
7
|
||||
# 115 s
|
||||
7
|
||||
# 116 t
|
||||
7
|
||||
# 117 u
|
||||
7
|
||||
# 118 v
|
||||
7
|
||||
# 119 w
|
||||
7
|
||||
# 120 x
|
||||
7
|
||||
# 121 y
|
||||
7
|
||||
# 122 z
|
||||
7
|
||||
# 123 {
|
||||
7
|
||||
# 124 |
|
||||
7
|
||||
# 125 }
|
||||
7
|
||||
# 126 ~
|
||||
7
|
||||
132
data/font/subatomic.fnt
Normal file
@@ -0,0 +1,132 @@
|
||||
# Font: subatomic — generado desde atomics.TTF size 6
|
||||
# Generado con tools/font_gen/font_gen.py
|
||||
|
||||
box_width 7
|
||||
box_height 7
|
||||
columns 15
|
||||
|
||||
# codepoint_decimal ancho_visual
|
||||
32 4 # U+0020
|
||||
33 1 # !
|
||||
34 3 # "
|
||||
35 5 # #
|
||||
36 5 # $
|
||||
37 5 # %
|
||||
38 6 # &
|
||||
39 1 # '
|
||||
40 2 # (
|
||||
41 2 # )
|
||||
42 5 # *
|
||||
43 5 # +
|
||||
44 1 # ,
|
||||
45 5 # -
|
||||
46 1 # .
|
||||
47 5 # /
|
||||
48 5 # 0
|
||||
49 2 # 1
|
||||
50 5 # 2
|
||||
51 5 # 3
|
||||
52 5 # 4
|
||||
53 5 # 5
|
||||
54 5 # 6
|
||||
55 5 # 7
|
||||
56 5 # 8
|
||||
57 5 # 9
|
||||
58 1 # :
|
||||
59 1 # ;
|
||||
60 3 # <
|
||||
61 5 # =
|
||||
62 3 # >
|
||||
63 4 # ?
|
||||
64 5 # @
|
||||
65 5 # A
|
||||
66 5 # B
|
||||
67 5 # C
|
||||
68 5 # D
|
||||
69 4 # E
|
||||
70 5 # F
|
||||
71 5 # G
|
||||
72 5 # H
|
||||
73 1 # I
|
||||
74 5 # J
|
||||
75 5 # K
|
||||
76 4 # L
|
||||
77 5 # M
|
||||
78 5 # N
|
||||
79 5 # O
|
||||
80 5 # P
|
||||
81 5 # Q
|
||||
82 5 # R
|
||||
83 5 # S
|
||||
84 5 # T
|
||||
85 5 # U
|
||||
86 5 # V
|
||||
87 5 # W
|
||||
88 5 # X
|
||||
89 5 # Y
|
||||
90 5 # Z
|
||||
91 2 # [
|
||||
92 5 # \
|
||||
93 2 # ]
|
||||
94 3 # ^
|
||||
95 5 # _
|
||||
96 2 # `
|
||||
97 4 # a
|
||||
98 4 # b
|
||||
99 3 # c
|
||||
100 4 # d
|
||||
101 4 # e
|
||||
102 3 # f
|
||||
103 4 # g
|
||||
104 4 # h
|
||||
105 1 # i
|
||||
106 2 # j
|
||||
107 3 # k
|
||||
108 1 # l
|
||||
109 5 # m
|
||||
110 4 # n
|
||||
111 4 # o
|
||||
112 4 # p
|
||||
113 4 # q
|
||||
114 3 # r
|
||||
115 4 # s
|
||||
116 2 # t
|
||||
117 4 # u
|
||||
118 4 # v
|
||||
119 5 # w
|
||||
120 3 # x
|
||||
121 4 # y
|
||||
122 4 # z
|
||||
123 3 # {
|
||||
124 1 # |
|
||||
125 3 # }
|
||||
126 4 # ~
|
||||
192 5 # À
|
||||
193 5 # Á
|
||||
200 4 # È
|
||||
201 4 # É
|
||||
205 1 # Í
|
||||
207 1 # Ï
|
||||
210 5 # Ò
|
||||
211 5 # Ó
|
||||
218 5 # Ú
|
||||
220 5 # Ü
|
||||
209 5 # Ñ
|
||||
199 5 # Ç
|
||||
224 4 # à
|
||||
225 4 # á
|
||||
232 4 # è
|
||||
233 4 # é
|
||||
237 1 # í
|
||||
239 1 # ï
|
||||
242 4 # ò
|
||||
243 4 # ó
|
||||
250 4 # ú
|
||||
252 4 # ü
|
||||
241 4 # ñ
|
||||
231 3 # ç
|
||||
161 1 # ¡
|
||||
191 4 # ¿
|
||||
171 3 # «
|
||||
187 3 # »
|
||||
183 1 # ·
|
||||
|
Before Width: | Height: | Size: 540 B After Width: | Height: | Size: 648 B |
@@ -1,194 +0,0 @@
|
||||
# box width
|
||||
7
|
||||
# box height
|
||||
7
|
||||
# 32 espacio ( )
|
||||
4
|
||||
# 33 !
|
||||
1
|
||||
# 34 "
|
||||
3
|
||||
# 35 #
|
||||
5
|
||||
# 36 $
|
||||
5
|
||||
# 37 %
|
||||
5
|
||||
# 38 &
|
||||
6
|
||||
# 39 '
|
||||
1
|
||||
# 40 (
|
||||
2
|
||||
# 41 )
|
||||
2
|
||||
# 42 *
|
||||
5
|
||||
# 43 +
|
||||
5
|
||||
# 44 ,
|
||||
1
|
||||
# 45 -
|
||||
5
|
||||
# 46 .
|
||||
1
|
||||
# 47 /
|
||||
5
|
||||
# 48 0
|
||||
5
|
||||
# 49 1
|
||||
2
|
||||
# 50 2
|
||||
5
|
||||
# 51 3
|
||||
5
|
||||
# 52 4
|
||||
5
|
||||
# 53 5
|
||||
5
|
||||
# 54 6
|
||||
5
|
||||
# 55 7
|
||||
5
|
||||
# 56 8
|
||||
5
|
||||
# 57 9
|
||||
5
|
||||
# 58 :
|
||||
1
|
||||
# 59 ;
|
||||
2
|
||||
# 60 <
|
||||
3
|
||||
# 61 =
|
||||
5
|
||||
# 62 >
|
||||
3
|
||||
# 63 ?
|
||||
4
|
||||
# 64 @
|
||||
5
|
||||
# 65 A
|
||||
5
|
||||
# 66 B
|
||||
5
|
||||
# 67 C
|
||||
5
|
||||
# 68 D
|
||||
5
|
||||
# 69 E
|
||||
4
|
||||
# 70 F
|
||||
5
|
||||
# 71 G
|
||||
5
|
||||
# 72 H
|
||||
5
|
||||
# 73 I
|
||||
1
|
||||
# 74 J
|
||||
5
|
||||
# 75 K
|
||||
5
|
||||
# 76 L
|
||||
2
|
||||
# 77 M
|
||||
5
|
||||
# 78 N
|
||||
5
|
||||
# 79 O
|
||||
5
|
||||
# 80 P
|
||||
5
|
||||
# 81 Q
|
||||
5
|
||||
# 82 R
|
||||
5
|
||||
# 83 S
|
||||
5
|
||||
# 84 T
|
||||
5
|
||||
# 85 U
|
||||
5
|
||||
# 86 V
|
||||
5
|
||||
# 87 W
|
||||
5
|
||||
# 88 X
|
||||
5
|
||||
# 89 Y
|
||||
5
|
||||
# 90 Z
|
||||
5
|
||||
# 91 [
|
||||
2
|
||||
# 92 \
|
||||
5
|
||||
# 93 ]
|
||||
2
|
||||
# 94 ^
|
||||
3
|
||||
# 95 _
|
||||
5
|
||||
# 96 `
|
||||
2
|
||||
# 97 a
|
||||
4
|
||||
# 98 b
|
||||
4
|
||||
# 99 c
|
||||
3
|
||||
# 100 d
|
||||
4
|
||||
# 101 e
|
||||
4
|
||||
# 102 f
|
||||
3
|
||||
# 103 g
|
||||
4
|
||||
# 104 h
|
||||
4
|
||||
# 105 i
|
||||
1
|
||||
# 106 j
|
||||
2
|
||||
# 107 k
|
||||
3
|
||||
# 108 l
|
||||
1
|
||||
# 109 m
|
||||
5
|
||||
# 110 n
|
||||
4
|
||||
# 111 o
|
||||
4
|
||||
# 112 p
|
||||
4
|
||||
# 113 q
|
||||
4
|
||||
# 114 r
|
||||
3
|
||||
# 115 s
|
||||
4
|
||||
# 116 t
|
||||
2
|
||||
# 117 u
|
||||
4
|
||||
# 118 v
|
||||
4
|
||||
# 119 w
|
||||
5
|
||||
# 120 x
|
||||
3
|
||||
# 121 y
|
||||
4
|
||||
# 122 z
|
||||
4
|
||||
# 123 {
|
||||
0
|
||||
# 124 |
|
||||
0
|
||||
# 125 }
|
||||
0
|
||||
# 126 ~
|
||||
0
|
||||
138
data/locale/ca.yaml
Normal file
@@ -0,0 +1,138 @@
|
||||
# JailDoctor's Dilemma - Catalan Locale
|
||||
# lang: ca
|
||||
|
||||
title:
|
||||
marquee: "EH JAILEROS!! ESTEM EN 2022 I ENCARA HO PETEM COM EN 1998!! QUE, HO HEU SENTIT O NO? ELS JAILGAMES HAN TORNAT!! SÍ, COLLONS, HAN TORNAT!! MÉS DE 10 TÍTOLS QUE EL JAILDOC TÉ A FOC LENT!! AIXÒ ÉS UNA BARBARITAT, PERÒ... QUIN EIXIRÀ PRIMER? I ATENCIÓ, QUE HI HA UN APARELLET NOU QUE VOS FARÀ VOLAR EL CAP: EL P.A.C.O.! PERÒ UN MOMENT... QUÈ ÉS AQUELL ENCANTET QUE VE ALLÀ? OOOH, AQUELLA MINIASCII ÉS AMOR DEL BO!! LI PEGARIA UNA MOSSEGADA A CADA BYTE! OSTRES! I NO VOS OBLIDEU DE PUJAR AQUELLS JAILGAMES VELLS I PANXUTS DE MS-DOS A GITHUB, QUE SI NO ES PERDRAN!! QUIN SERÀ EL PROPER PROJECTE DEL JAILDOC? QUÈ PRENDRA VIDA? AI MARE... NI IDEA, PERÒ ACÍ PODEU SABER-HO SI RESOLGUEU EL DILEMA DEL JAILDOCTOR... VOS ATREVIU O QUÈ?"
|
||||
menu:
|
||||
play: "1. JUGAR"
|
||||
keyboard: "2. REDEFINIR TECLAT"
|
||||
joystick: "3. REDEFINIR MANDO"
|
||||
projects: "4. PROJECTES"
|
||||
keys:
|
||||
prompt0: "PREM UNA TECLA PER A ESQUERRA"
|
||||
prompt1: "PREM UNA TECLA PER A DRETA"
|
||||
prompt2: "PREM UNA TECLA PER A SALTAR"
|
||||
defined: "TECLES DEFINIDES"
|
||||
label0: "ESQUERRA: "
|
||||
label1: "DRETA: "
|
||||
label2: "SALTAR: "
|
||||
invalid: "TECLA INVÀLIDA! PROVA'N UNA ALTRA"
|
||||
already_used: "TECLA JA USADA! PROVA'N UNA ALTRA"
|
||||
buttons:
|
||||
prompt0: "PREM UN BOTÓ PER A ESQUERRA"
|
||||
prompt1: "PREM UN BOTÓ PER A DRETA"
|
||||
prompt2: "PREM UN BOTÓ PER A SALTAR"
|
||||
defined: "BOTONS DEFINITS"
|
||||
already_used: "BOTÓ JA USAT! PROVA'N UN ALTRE"
|
||||
projects: "PROJECTES"
|
||||
|
||||
game_over:
|
||||
title: "G A M E O V E R"
|
||||
items: "OBJECTES: "
|
||||
rooms: "SALES: "
|
||||
worst_nightmare: "EL TEU PITJOR MALSON ÉS"
|
||||
|
||||
ending:
|
||||
t0: "FINALMENT HO VA ACONSEGUIR"
|
||||
t1: "ARRIBAR A LA JAIL"
|
||||
t2: "AMB TOTS ELS SEUS PROJECTES"
|
||||
t3: "A PUNT D'ALLIBERAR-LOS"
|
||||
t4: "ALLÍ ESTAVEN TOTS ELS JAILERS"
|
||||
t5: "ESPERANT QUE ELS JAILGAMES"
|
||||
t6: "FOREN ALLIBERATS"
|
||||
t7: "HI HAVIA FINS I TOT BARRULLS"
|
||||
t8: "I BEGGINERS ENTRE LA GENT"
|
||||
t9: "BRY ESTAVA FENT LLAGRIMETA..."
|
||||
t10: "PERÒ DE SOBTE ALGUNA COSA"
|
||||
t11: "LI VA CRIDAR L'ATENCIÓ"
|
||||
t12: "UN MUNT DE FERRALLA!"
|
||||
t13: "PLE D'ANDROMINES QUE NI ANAVEN!!"
|
||||
t14: "I ALESHORES,"
|
||||
t15: "QUARANTA PROJECTES NOUS"
|
||||
t16: "VAN NÀIXER..."
|
||||
|
||||
ending2:
|
||||
starring: "PROTAGONISTES"
|
||||
jaildoctor: "JAILDOCTOR"
|
||||
thank_you: "GRÀCIES"
|
||||
for_playing: "PER JUGAR!"
|
||||
|
||||
credits:
|
||||
instructions: "INSTRUCCIONS:"
|
||||
l0: "AJUDA A JAILDOC A RECUPERAR"
|
||||
l1: "ELS SEUS PROJECTES I ARRIBAR"
|
||||
l2: "A LA JAIL PER ACABAR-LOS"
|
||||
keys: "TECLES:"
|
||||
keys_move: "CURSORS PER A MOURE I SALTAR"
|
||||
f8: "F8 ACTIVAR/DESACTIVAR MÚSICA"
|
||||
f11: "F11 PAUSAR EL JOC"
|
||||
f1f2: "F1-F2 MIDA DE LA FINESTRA"
|
||||
f3: "F3 PANTALLA COMPLETA"
|
||||
f9: "F9 VORA DE LA PANTALLA"
|
||||
author: "UN JOC DE JAILDESIGNER"
|
||||
date: "FET A L'ESTIU/TARDOR DEL 2022"
|
||||
love: "M'ENCANTEN ELS JAILGAMES!"
|
||||
|
||||
achievements:
|
||||
header: "ASSOLIMENT DESBLOQUEJAT!"
|
||||
c1: "COSES BRILLANTS"
|
||||
d1: "Aconseguiu el 25% dels objectes"
|
||||
c2: "A MITJAN CAMÍ"
|
||||
d2: "Aconseguiu el 50% dels objectes"
|
||||
c3: "QUASI HI SOM"
|
||||
d3: "Aconseguiu el 75% dels objectes"
|
||||
c4: "EL COL·LECCIONISTA"
|
||||
d4: "Aconseguiu el 100% dels objectes"
|
||||
c5: "PASSEJANT PER ACÍ"
|
||||
d5: "Visiteu 20 sales"
|
||||
c6: "M'HE PERDUT"
|
||||
d6: "Visiteu 40 sales"
|
||||
c7: "M'AGRADA EXPLORAR"
|
||||
d7: "Visiteu totes les sales"
|
||||
c8: "JA ESTÀ?"
|
||||
d8: "Completeu el joc"
|
||||
c9: "UN FORAT EM VA ENGOLIR"
|
||||
d9: "Completeu el joc sense entrar a la presó"
|
||||
c10: "ELS MEUS PROJECTES"
|
||||
d10: "Completeu el joc amb tots els objectes"
|
||||
c11: "M'AGRADEN ELS MEUS AMICS DE COLORS"
|
||||
d11: "Completeu el joc sense morir"
|
||||
c12: "PROJECTES A CORRE-CUITA"
|
||||
d12: "Completeu el joc en menys de 30 minuts"
|
||||
|
||||
ui:
|
||||
press_again_menu: "PREM DE NOU PER TORNAR AL MENÚ"
|
||||
press_again_exit: "PREM DE NOU PER EIXIR"
|
||||
border_enabled: "VORA ACTIVADA"
|
||||
border_disabled: "VORA DESACTIVADA"
|
||||
fullscreen_enabled: "PANTALLA COMPLETA ACTIVADA"
|
||||
fullscreen_disabled: "PANTALLA COMPLETA DESACTIVADA"
|
||||
window_zoom: "ZOOM FINESTRA x"
|
||||
postfx_enabled: "POSTFX ACTIVAT"
|
||||
postfx_disabled: "POSTFX DESACTIVAT"
|
||||
postfx: "POSTFX"
|
||||
supersampling_enabled: "SUPERMOSTREIG ACTIVAT"
|
||||
supersampling_disabled: "SUPERMOSTREIG DESACTIVAT"
|
||||
palette: "PALETA"
|
||||
integer_scale_enabled: "ESCALAT SENCER ACTIVAT"
|
||||
integer_scale_disabled: "ESCALAT SENCER DESACTIVAT"
|
||||
vsync_enabled: "V-SYNC ACTIVAT"
|
||||
vsync_disabled: "V-SYNC DESACTIVAT"
|
||||
|
||||
scoreboard:
|
||||
items: "TRESORS PILLATS "
|
||||
time: " HORA "
|
||||
rooms: "SALES"
|
||||
|
||||
game:
|
||||
music_enabled: "MÚSICA ACTIVADA"
|
||||
music_disabled: "MÚSICA DESACTIVADA"
|
||||
paused: "JOC EN PAUSA"
|
||||
running: "JOC EN MARXA"
|
||||
enabled: " ACTIVAT"
|
||||
disabled: " DESACTIVAT"
|
||||
cheat_infinite_lives: "VIDES INFINITES"
|
||||
cheat_invincible: "INVENCIBLE"
|
||||
cheat_jail_open: "JAIL OBERTA"
|
||||
debug_enabled: "DEBUG ACTIVAT"
|
||||
debug_disabled: "DEBUG DESACTIVAT"
|
||||
138
data/locale/en.yaml
Normal file
@@ -0,0 +1,138 @@
|
||||
# JailDoctor's Dilemma - English Locale
|
||||
# lang: en
|
||||
|
||||
title:
|
||||
marquee: "HEY JAILERS!! IT'S 2022 AND WE'RE STILL ROCKING LIKE IT'S 1998!!! HAVE YOU HEARD IT? JAILGAMES ARE BACK!! YEEESSS BACK!! MORE THAN 10 TITLES ON JAILDOC'S KITCHEN!! THATS A LOOOOOOT OF JAILGAMES, BUT WHICH ONE WILL STRIKE FIRST? THERE IS ALSO A NEW DEVICE TO COME THAT WILL BLOW YOUR MIND WITH JAILGAMES ON THE GO: P.A.C.O. BUT WAIT! WHAT'S THAT BEAUTY I'M SEEING RIGHT OVER THERE?? OOOH THAT TINY MINIASCII IS PURE LOVE!! I WANT TO LICK EVERY BYTE OF IT!! OH SHIT! AND DON'T FORGET TO BRING BACK THOSE OLD AND FAT MS-DOS JAILGAMES TO GITHUB TO KEEP THEM ALIVE!! WHAT WILL BE THE NEXT JAILDOC RELEASE? WHAT WILL BE THE NEXT PROJECT TO COME ALIVE?? OH BABY WE DON'T KNOW BUT HERE YOU CAN FIND THE ANSWER, YOU JUST HAVE TO COMPLETE JAILDOCTOR'S DILEMMA ... COULD YOU?"
|
||||
menu:
|
||||
play: "1. PLAY"
|
||||
keyboard: "2. REDEFINE KEYBOARD"
|
||||
joystick: "3. REDEFINE JOYSTICK"
|
||||
projects: "4. PROJECTS"
|
||||
keys:
|
||||
prompt0: "PRESS KEY FOR LEFT"
|
||||
prompt1: "PRESS KEY FOR RIGHT"
|
||||
prompt2: "PRESS KEY FOR JUMP"
|
||||
defined: "KEYS DEFINED"
|
||||
label0: "LEFT: "
|
||||
label1: "RIGHT: "
|
||||
label2: "JUMP: "
|
||||
invalid: "INVALID KEY! TRY ANOTHER"
|
||||
already_used: "KEY ALREADY USED! TRY ANOTHER"
|
||||
buttons:
|
||||
prompt0: "PRESS BUTTON FOR LEFT"
|
||||
prompt1: "PRESS BUTTON FOR RIGHT"
|
||||
prompt2: "PRESS BUTTON FOR JUMP"
|
||||
defined: "BUTTONS DEFINED"
|
||||
already_used: "BUTTON ALREADY USED! TRY ANOTHER"
|
||||
projects: "PROJECTS"
|
||||
|
||||
game_over:
|
||||
title: "G A M E O V E R"
|
||||
items: "ITEMS: "
|
||||
rooms: "ROOMS: "
|
||||
worst_nightmare: "YOUR WORST NIGHTMARE IS"
|
||||
|
||||
ending:
|
||||
t0: "HE FINALLY MANAGED"
|
||||
t1: "TO GET TO THE JAIL"
|
||||
t2: "WITH ALL HIS PROJECTS"
|
||||
t3: "READY TO BE FREED"
|
||||
t4: "ALL THE JAILERS WERE THERE"
|
||||
t5: "WAITING FOR THE JAILGAMES"
|
||||
t6: "TO BE RELEASED"
|
||||
t7: "THERE WERE EVEN BARRULLS AND"
|
||||
t8: "BEGINNERS AMONG THE CROWD"
|
||||
t9: "BRY WAS CRYING..."
|
||||
t10: "BUT SUDDENLY SOMETHING"
|
||||
t11: "CAUGHT HIS ATTENTION"
|
||||
t12: "A PILE OF JUNK!"
|
||||
t13: "FULL OF NON WORKING TRASH!!"
|
||||
t14: "AND THEN,"
|
||||
t15: "FOURTY NEW PROJECTS"
|
||||
t16: "WERE BORN..."
|
||||
|
||||
ending2:
|
||||
starring: "STARRING"
|
||||
jaildoctor: "JAILDOCTOR"
|
||||
thank_you: "THANK YOU"
|
||||
for_playing: "FOR PLAYING!"
|
||||
|
||||
credits:
|
||||
instructions: "INSTRUCTIONS:"
|
||||
l0: "HELP JAILDOC TO GET BACK ALL"
|
||||
l1: "HIS PROJECTS AND GO TO THE"
|
||||
l2: "JAIL TO FINISH THEM"
|
||||
keys: "KEYS:"
|
||||
keys_move: "CURSORS TO MOVE AND JUMP"
|
||||
f8: "F8 TOGGLE THE MUSIC"
|
||||
f11: "F11 PAUSE THE GAME"
|
||||
f1f2: "F1-F2 WINDOWS SIZE"
|
||||
f3: "F3 TOGGLE FULLSCREEN"
|
||||
f9: "F9 TOOGLE BORDER SCREEN"
|
||||
author: "A GAME BY JAILDESIGNER"
|
||||
date: "MADE ON SUMMER/FALL 2022"
|
||||
love: "I LOVE JAILGAMES! "
|
||||
|
||||
achievements:
|
||||
header: "ACHIEVEMENT UNLOCKED!"
|
||||
c1: "SHINY THINGS"
|
||||
d1: "Get 25% of the items"
|
||||
c2: "HALF THE WORK"
|
||||
d2: "Get 50% of the items"
|
||||
c3: "GETTING THERE"
|
||||
d3: "Get 75% of the items"
|
||||
c4: "THE COLLECTOR"
|
||||
d4: "Get 100% of the items"
|
||||
c5: "WANDERING AROUND"
|
||||
d5: "Visit 20 rooms"
|
||||
c6: "I GOT LOST"
|
||||
d6: "Visit 40 rooms"
|
||||
c7: "I LIKE TO EXPLORE"
|
||||
d7: "Visit all rooms"
|
||||
c8: "FINISH THE GAME"
|
||||
d8: "Complete the game"
|
||||
c9: "I WAS SUCKED BY A HOLE"
|
||||
d9: "Complete the game without entering the jail"
|
||||
c10: "MY LITTLE PROJECTS"
|
||||
d10: "Complete the game with all items"
|
||||
c11: "I LIKE MY MULTICOLOURED FRIENDS"
|
||||
d11: "Complete the game without dying"
|
||||
c12: "SHIT PROJECTS DONE FAST"
|
||||
d12: "Complete the game in under 30 minutes"
|
||||
|
||||
ui:
|
||||
press_again_menu: "PRESS AGAIN TO RETURN TO MENU"
|
||||
press_again_exit: "PRESS AGAIN TO EXIT"
|
||||
border_enabled: "BORDER ENABLED"
|
||||
border_disabled: "BORDER DISABLED"
|
||||
fullscreen_enabled: "FULLSCREEN ENABLED"
|
||||
fullscreen_disabled: "FULLSCREEN DISABLED"
|
||||
window_zoom: "WINDOW ZOOM x"
|
||||
postfx_enabled: "POSTFX ENABLED"
|
||||
postfx_disabled: "POSTFX DISABLED"
|
||||
postfx: "POSTFX"
|
||||
supersampling_enabled: "SUPERSAMPLING ON"
|
||||
supersampling_disabled: "SUPERSAMPLING OFF"
|
||||
palette: "PALETTE"
|
||||
integer_scale_enabled: "INTEGER SCALE ENABLED"
|
||||
integer_scale_disabled: "INTEGER SCALE DISABLED"
|
||||
vsync_enabled: "V-SYNC ENABLED"
|
||||
vsync_disabled: "V-SYNC DISABLED"
|
||||
|
||||
scoreboard:
|
||||
items: "ITEMS COLLECTED "
|
||||
time: " TIME "
|
||||
rooms: "ROOMS"
|
||||
|
||||
game:
|
||||
music_enabled: "MUSIC ENABLED"
|
||||
music_disabled: "MUSIC DISABLED"
|
||||
paused: "GAME PAUSED"
|
||||
running: "GAME RUNNING"
|
||||
enabled: " ENABLED"
|
||||
disabled: " DISABLED"
|
||||
cheat_infinite_lives: "INFINITE LIVES"
|
||||
cheat_invincible: "INVINCIBLE"
|
||||
cheat_jail_open: "JAIL IS OPEN"
|
||||
debug_enabled: "DEBUG ENABLED"
|
||||
debug_disabled: "DEBUG DISABLED"
|
||||
@@ -1,6 +1,7 @@
|
||||
# THE JAIL
|
||||
room:
|
||||
name: "THE JAIL"
|
||||
name_en: "THE JAIL"
|
||||
name_ca: "LA JAIL"
|
||||
bgColor: bright_blue
|
||||
border: blue
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# ROAD TO THE JAIL
|
||||
room:
|
||||
name: "ROAD TO THE JAIL"
|
||||
name_en: "ROAD TO THE JAIL"
|
||||
name_ca: "CAMI A LA JAIL"
|
||||
bgColor: black
|
||||
border: blue
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# VOID MAIN
|
||||
room:
|
||||
name: "VOID MAIN"
|
||||
name_en: "VOID MAIN"
|
||||
name_ca: "VOID MAIN"
|
||||
bgColor: black
|
||||
border: magenta
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# JUMP THROUGH
|
||||
room:
|
||||
name: "JUMP THROUGH"
|
||||
name_en: "JUMP THROUGH"
|
||||
name_ca: "SALTA A TRAVES"
|
||||
bgColor: black
|
||||
border: cyan
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# BIG JUMP
|
||||
room:
|
||||
name: "BIG JUMP"
|
||||
name_en: "BIG JUMP"
|
||||
name_ca: "GRAN SALT"
|
||||
bgColor: black
|
||||
border: red
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# WELCOME TO MY ABBEY
|
||||
room:
|
||||
name: "WELCOME TO MY ABBEY"
|
||||
name_en: "WELCOME TO MY ABBEY"
|
||||
name_ca: "BENVINGUT A LA MEVA ABADIA"
|
||||
bgColor: blue
|
||||
border: yellow
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# SIGMASUA > TELEGRAM
|
||||
room:
|
||||
name: "SIGMASUA > TELEGRAM"
|
||||
name_en: "SIGMASUA > TELEGRAM"
|
||||
name_ca: "SIGMASUA > TELEGRAM"
|
||||
bgColor: black
|
||||
border: blue
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# THE GARDEN
|
||||
room:
|
||||
name: "THE GARDEN"
|
||||
name_en: "THE GARDEN"
|
||||
name_ca: "EL JARDI"
|
||||
bgColor: black
|
||||
border: cyan
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# THE BIG TREE
|
||||
room:
|
||||
name: "THE BIG TREE"
|
||||
name_en: "THE BIG TREE"
|
||||
name_ca: "EL GRAN ARBRE"
|
||||
bgColor: black
|
||||
border: bright_blue
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# TREE TOP
|
||||
room:
|
||||
name: "TREE TOP"
|
||||
name_en: "TREE TOP"
|
||||
name_ca: "AMUNT DE L'ARBRE"
|
||||
bgColor: bright_black
|
||||
border: blue
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# LAZY ROOM
|
||||
room:
|
||||
name: "LAZY ROOM"
|
||||
name_en: "LAZY ROOM"
|
||||
name_ca: "SALA DE LA PEREA"
|
||||
bgColor: black
|
||||
border: blue
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# THE PASSAGE
|
||||
room:
|
||||
name: "THE PASSAGE"
|
||||
name_en: "THE PASSAGE"
|
||||
name_ca: "EL PASSATGE"
|
||||
bgColor: black
|
||||
border: green
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# TUNO KILLER
|
||||
room:
|
||||
name: "TUNO KILLER"
|
||||
name_en: "TUNO KILLER"
|
||||
name_ca: "MATATUNOS"
|
||||
bgColor: black
|
||||
border: blue
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# KILLING SPREE
|
||||
room:
|
||||
name: "KILLING SPREE"
|
||||
name_en: "KILLING SPREE"
|
||||
name_ca: "MATANCA INDISCRIMINADA"
|
||||
bgColor: black
|
||||
border: blue
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# NOW THIS IS THE BATCAVE!
|
||||
room:
|
||||
name: "NOW THIS IS THE BATCAVE!"
|
||||
name_en: "NOW THIS IS THE BATCAVE!"
|
||||
name_ca: "AQUESTA SI QUE ES LA BATCOVA!"
|
||||
bgColor: black
|
||||
border: black
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# THE FRIDGE
|
||||
room:
|
||||
name: "THE FRIDGE"
|
||||
name_en: "THE FRIDGE"
|
||||
name_ca: "LA NEVERA"
|
||||
bgColor: blue
|
||||
border: blue
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# I DID NOT COPY THIS ONE
|
||||
room:
|
||||
name: "I DID NOT COPY THIS ONE"
|
||||
name_en: "I DID NOT COPY THIS ONE"
|
||||
name_ca: "ESTA NO LA HE COPIADA, NO"
|
||||
bgColor: black
|
||||
border: magenta
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# MAKE MONEY
|
||||
room:
|
||||
name: "MAKE MONEY"
|
||||
name_en: "MAKE MONEY"
|
||||
name_ca: "INHERITEDS!"
|
||||
bgColor: black
|
||||
border: yellow
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# THIS CAN'T BE THE BATCAVE
|
||||
room:
|
||||
name: "THIS CAN'T BE THE BATCAVE"
|
||||
name_en: "THIS CAN'T BE THE BATCAVE"
|
||||
name_ca: "AQUESTA NO POT SER LA BATCOVA"
|
||||
bgColor: black
|
||||
border: cyan
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# ENTRANCE TO THE VALLEY
|
||||
room:
|
||||
name: "ENTRANCE TO THE VALLEY"
|
||||
name_en: "ENTRANCE TO THE VALLEY"
|
||||
name_ca: "ENTRADA A LA VALL"
|
||||
bgColor: black
|
||||
border: red
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# ENTER PAKU SIMBEL
|
||||
room:
|
||||
name: "ENTER PAKU SIMBEL"
|
||||
name_en: "ENTER PAKU SIMBEL"
|
||||
name_ca: "ENTRANT A PAKU SIMBEL"
|
||||
bgColor: bright_black
|
||||
border: yellow
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# AEE REMAKE, PLEASE
|
||||
room:
|
||||
name: "AEE REMAKE, PLEASE"
|
||||
name_en: "AEE REMAKE, PLEASE"
|
||||
name_ca: "AEE REMAKE, PERFAPLIS"
|
||||
bgColor: bright_black
|
||||
border: yellow
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# INNER CHAMBER
|
||||
room:
|
||||
name: "INNER CHAMBER"
|
||||
name_en: "INNER CHAMBER"
|
||||
name_ca: "CAMBRA INTERIOR"
|
||||
bgColor: black
|
||||
border: bright_yellow
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# PLAY IT AGAIN, SAM
|
||||
room:
|
||||
name: "PLAY IT AGAIN, SAM"
|
||||
name_en: "PLAY IT AGAIN, SAM"
|
||||
name_ca: "TORNA-LA A TOCAR, SAM"
|
||||
bgColor: black
|
||||
border: bright_yellow
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# THE CHAPPEL
|
||||
room:
|
||||
name: "THE CHAPPEL"
|
||||
name_en: "THE CHAPPEL"
|
||||
name_ca: "LA CAPELLA"
|
||||
bgColor: blue
|
||||
border: yellow
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# JINGLE BELLS
|
||||
room:
|
||||
name: "JINGLE BELLS"
|
||||
name_en: "JINGLE BELLS"
|
||||
name_ca: "CAMPANETES"
|
||||
bgColor: blue
|
||||
border: yellow
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# THE BACKYARD
|
||||
room:
|
||||
name: "THE BACKYARD"
|
||||
name_en: "THE BACKYARD"
|
||||
name_ca: "EL PATI DE DARRERE"
|
||||
bgColor: blue
|
||||
border: cyan
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# YOU SHALL NOT PASS
|
||||
room:
|
||||
name: "YOU SHALL NOT PASS"
|
||||
name_en: "YOU SHALL NOT PASS"
|
||||
name_ca: "NO PASSARAS"
|
||||
bgColor: bright_black
|
||||
border: black
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# QUO VOIDIS
|
||||
room:
|
||||
name: "QUO VOIDIS"
|
||||
name_en: "QUO VOIDIS"
|
||||
name_ca: "QUO VOIDIS"
|
||||
bgColor: blue
|
||||
border: bright_black
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# QVOID IS A JAILGAME!
|
||||
room:
|
||||
name: "QVOID IS A JAILGAME!"
|
||||
name_en: "QVOID IS A JAILGAME!"
|
||||
name_ca: "QVOID ES UN JAILGAME!"
|
||||
bgColor: blue
|
||||
border: bright_black
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# 256 COLORS
|
||||
room:
|
||||
name: "256 COLORS"
|
||||
name_en: "256 COLORS"
|
||||
name_ca: "256 COLORS"
|
||||
bgColor: black
|
||||
border: bright_magenta
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# ...?
|
||||
room:
|
||||
name: "...?"
|
||||
name_en: "...?"
|
||||
name_ca: "...?"
|
||||
bgColor: black
|
||||
border: cyan
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# } WE ALL LOVE JAILGAMES }
|
||||
room:
|
||||
name: "} WE ALL LOVE JAILGAMES }"
|
||||
name_en: "} WE ALL LOVE JAILGAMES }"
|
||||
name_ca: "} AMOR PELS JAILGAMES }"
|
||||
bgColor: black
|
||||
border: bright_black
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# ULA HOP!
|
||||
room:
|
||||
name: "ULA HOP!"
|
||||
name_en: "ULA HOP!"
|
||||
name_ca: "ULA HOP!"
|
||||
bgColor: black
|
||||
border: cyan
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# SILICON BOOBS
|
||||
room:
|
||||
name: "SILICON BOOBS"
|
||||
name_en: "SILICON BOOBS"
|
||||
name_ca: "MAMELLES DE SILICI"
|
||||
bgColor: black
|
||||
border: bright_green
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# BE CAREFUL WITH THE FUSE
|
||||
room:
|
||||
name: "BE CAREFUL WITH THE FUSE"
|
||||
name_en: "BE CAREFUL WITH THE FUSE"
|
||||
name_ca: "COMPTE AMB EL FUSIBLE"
|
||||
bgColor: black
|
||||
border: bright_cyan
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# CHIP'N CHIP
|
||||
room:
|
||||
name: "CHIP'N CHIP"
|
||||
name_en: "CHIP'N CHIP"
|
||||
name_ca: "CHIP'N CHIP"
|
||||
bgColor: black
|
||||
border: bright_green
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# THE FINAL CROSSOVER
|
||||
room:
|
||||
name: "THE FINAL CROSSOVER"
|
||||
name_en: "THE FINAL CROSSOVER"
|
||||
name_ca: "EL CROSSOVER DEFINITIU"
|
||||
bgColor: bright_black
|
||||
border: yellow
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# YOU'LL BELIEVE AROUNDER CAN FLY
|
||||
room:
|
||||
name: "YOU'LL BELIEVE AROUNDER CAN FLY"
|
||||
name_en: "YOU'LL BELIEVE AROUNDER CAN FLY"
|
||||
name_ca: "CREURAS QUE ELS AROUNDERS VOLEN"
|
||||
bgColor: black
|
||||
border: cyan
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# PREVENT THE CRISIS
|
||||
room:
|
||||
name: "PREVENT THE CRISIS"
|
||||
name_en: "PREVENT THE CRISIS"
|
||||
name_ca: "PREVEU LA CRISI"
|
||||
bgColor: black
|
||||
border: bright_magenta
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# AROUND WITH ME
|
||||
room:
|
||||
name: "AROUND WITH ME"
|
||||
name_en: "AROUND WITH ME"
|
||||
name_ca: "VOLTA AMB MI"
|
||||
bgColor: black
|
||||
border: blue
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# P.A.C.O. ON THE GO
|
||||
room:
|
||||
name: "P.A.C.O. ON THE GO"
|
||||
name_en: "P.A.C.O. ON THE GO"
|
||||
name_ca: "P.A.C.O. EN MARXA"
|
||||
bgColor: black
|
||||
border: blue
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# THE TUBE
|
||||
room:
|
||||
name: "THE TUBE"
|
||||
name_en: "THE TUBE"
|
||||
name_ca: "EL TUB"
|
||||
bgColor: black
|
||||
border: blue
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# SANDWITCH AND COUNTER
|
||||
room:
|
||||
name: "SANDWITCH AND COUNTER"
|
||||
name_en: "SANDWITCH AND COUNTER"
|
||||
name_ca: "SANDVITX I COUNTER S."
|
||||
bgColor: black
|
||||
border: cyan
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# FEEL THE PRESSURE
|
||||
room:
|
||||
name: "FEEL THE PRESSURE"
|
||||
name_en: "FEEL THE PRESSURE"
|
||||
name_ca: "NOTA LA PRESSIO"
|
||||
bgColor: bright_black
|
||||
border: bright_yellow
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# FEEL THE HEAT
|
||||
room:
|
||||
name: "FEEL THE HEAT"
|
||||
name_en: "FEEL THE HEAT"
|
||||
name_ca: "NOTA LA CALOR"
|
||||
bgColor: bright_black
|
||||
border: bright_yellow
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# THE BATTLE NEVER ENDS
|
||||
room:
|
||||
name: "THE BATTLE NEVER ENDS"
|
||||
name_en: "THE BATTLE NEVER ENDS"
|
||||
name_ca: "LA BATALLA MAI ACABA"
|
||||
bgColor: black
|
||||
border: white
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# WELCOME TO THE JAILBATTLE
|
||||
room:
|
||||
name: "WELCOME TO THE JAILBATTLE"
|
||||
name_en: "WELCOME TO THE JAILBATTLE"
|
||||
name_ca: "BENVINGUTS A JAILBATTLE"
|
||||
bgColor: green
|
||||
border: bright_green
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# WE NEED A ROBOT
|
||||
room:
|
||||
name: "WE NEED A ROBOT"
|
||||
name_en: "WE NEED A ROBOT"
|
||||
name_ca: "NECESSITEM UN ROBOT"
|
||||
bgColor: black
|
||||
border: red
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# STORED JAILGAMES
|
||||
room:
|
||||
name: "STORED JAILGAMES"
|
||||
name_en: "STORED JAILGAMES"
|
||||
name_ca: "JAILGAMES EMMAGATZEMATS"
|
||||
bgColor: black
|
||||
border: blue
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# MINI ASCII
|
||||
room:
|
||||
name: "MINI ASCII"
|
||||
name_en: "MINI ASCII"
|
||||
name_ca: "MINI ASCII"
|
||||
bgColor: black
|
||||
border: black
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# BREAKOUT.LUA
|
||||
room:
|
||||
name: "BREAKOUT.LUA"
|
||||
name_en: "BREAKOUT.LUA"
|
||||
name_ca: "BREAKOUT.LUA"
|
||||
bgColor: black
|
||||
border: black
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# P.A.C.O. WORKSHOP
|
||||
room:
|
||||
name: "P.A.C.O. WORKSHOP"
|
||||
name_en: "P.A.C.O. WORKSHOP"
|
||||
name_ca: "TALLER DE P.A.C.O."
|
||||
bgColor: black
|
||||
border: yellow
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# THE BASEMENT
|
||||
room:
|
||||
name: "THE BASEMENT"
|
||||
name_en: "THE BASEMENT"
|
||||
name_ca: "EL SOTAN"
|
||||
bgColor: black
|
||||
border: blue
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# THAT'S A GUITAR
|
||||
room:
|
||||
name: "THAT'S A GUITAR"
|
||||
name_en: "THAT'S A GUITAR"
|
||||
name_ca: "AIXO ES UNA GUITARRA"
|
||||
bgColor: black
|
||||
border: black
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# HEAVY DEMONS ON LEGGINS
|
||||
room:
|
||||
name: "HEAVY DEMONS ON LEGGINS"
|
||||
name_en: "HEAVY DEMONS ON LEGGINS"
|
||||
name_ca: "DIMONIS HEAVIES AMB MALLES"
|
||||
bgColor: black
|
||||
border: black
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# JAILGAMES GO TO HELL
|
||||
room:
|
||||
name: "JAILGAMES GO TO HELL"
|
||||
name_en: "JAILGAMES GO TO HELL"
|
||||
name_ca: "JAILGAMES A L'INFERN"
|
||||
bgColor: red
|
||||
border: bright_red
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# CHIRPING
|
||||
room:
|
||||
name: "CHIRPING"
|
||||
name_en: "CHIRPING DEVELOPMENT"
|
||||
name_ca: "DESENVOLUPANT CHIRPING"
|
||||
bgColor: black
|
||||
border: magenta
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# STATIC
|
||||
room:
|
||||
name: "STATIC"
|
||||
name_en: "STATIC"
|
||||
name_ca: "ESTATICA"
|
||||
bgColor: black
|
||||
border: bright_magenta
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# MAGNETIC FIELDS
|
||||
room:
|
||||
name: "MAGNETIC FIELDS"
|
||||
name_en: "MAGNETIC FIELDS"
|
||||
name_ca: "CAMPS MAGNETICS"
|
||||
bgColor: black
|
||||
border: bright_red
|
||||
tileSetFile: standard.gif
|
||||
|
||||
@@ -22,6 +22,10 @@ layout(set = 3, binding = 0) uniform PostFXUniforms {
|
||||
float gamma_strength;
|
||||
float curvature;
|
||||
float bleeding;
|
||||
float pixel_scale; // physical pixels per logical pixel (vh / tex_height_)
|
||||
float time; // seconds since SDL init
|
||||
float oversample; // supersampling factor (1.0 = off, 3.0 = 3×SS)
|
||||
float flicker; // 0 = off, 1 = phosphor flicker ~50 Hz — 48 bytes total (3 × 16)
|
||||
} u;
|
||||
|
||||
// YCbCr helpers for NTSC bleeding
|
||||
@@ -64,23 +68,25 @@ void main() {
|
||||
// Muestra base
|
||||
vec3 base = texture(scene, uv).rgb;
|
||||
|
||||
// Sangrado NTSC — difuminado horizontal de crominancia
|
||||
// Sangrado NTSC — difuminado horizontal de crominancia.
|
||||
// step = 1 pixel lógico de juego en UV (corrige SS: textureSize.x = game_w * oversample).
|
||||
vec3 colour;
|
||||
if (u.bleeding > 0.0) {
|
||||
float tw = float(textureSize(scene, 0).x);
|
||||
float tw = float(textureSize(scene, 0).x);
|
||||
float step = u.oversample / tw; // 1 pixel lógico en UV
|
||||
vec3 ycc = rgb_to_ycc(base);
|
||||
vec3 ycc_l2 = rgb_to_ycc(texture(scene, uv - vec2(2.0/tw, 0.0)).rgb);
|
||||
vec3 ycc_l1 = rgb_to_ycc(texture(scene, uv - vec2(1.0/tw, 0.0)).rgb);
|
||||
vec3 ycc_r1 = rgb_to_ycc(texture(scene, uv + vec2(1.0/tw, 0.0)).rgb);
|
||||
vec3 ycc_r2 = rgb_to_ycc(texture(scene, uv + vec2(2.0/tw, 0.0)).rgb);
|
||||
vec3 ycc_l2 = rgb_to_ycc(texture(scene, uv - vec2(2.0*step, 0.0)).rgb);
|
||||
vec3 ycc_l1 = rgb_to_ycc(texture(scene, uv - vec2(1.0*step, 0.0)).rgb);
|
||||
vec3 ycc_r1 = rgb_to_ycc(texture(scene, uv + vec2(1.0*step, 0.0)).rgb);
|
||||
vec3 ycc_r2 = rgb_to_ycc(texture(scene, uv + vec2(2.0*step, 0.0)).rgb);
|
||||
ycc.yz = (ycc_l2.yz + ycc_l1.yz*2.0 + ycc.yz*2.0 + ycc_r1.yz*2.0 + ycc_r2.yz) / 8.0;
|
||||
colour = mix(base, ycc_to_rgb(ycc), u.bleeding);
|
||||
} else {
|
||||
colour = base;
|
||||
}
|
||||
|
||||
// Aberración cromática
|
||||
float ca = u.chroma_strength * 0.005;
|
||||
// Aberración cromática (drift animado con time para efecto NTSC real)
|
||||
float ca = u.chroma_strength * 0.005 * (1.0 + 0.15 * sin(u.time * 7.3));
|
||||
colour.r = texture(scene, uv + vec2(ca, 0.0)).r;
|
||||
colour.b = texture(scene, uv - vec2(ca, 0.0)).b;
|
||||
|
||||
@@ -90,14 +96,19 @@ void main() {
|
||||
colour = mix(colour, lin, u.gamma_strength);
|
||||
}
|
||||
|
||||
// Scanlines
|
||||
float texHeight = float(textureSize(scene, 0).y);
|
||||
float scaleY = u.screen_height / texHeight;
|
||||
float screenY = uv.y * u.screen_height;
|
||||
float posInRow = mod(screenY, scaleY);
|
||||
float scanLineDY = posInRow / scaleY - 0.5;
|
||||
float scan = max(1.0 - scanLineDY * scanLineDY * 6.0, 0.12) * 3.5;
|
||||
colour *= mix(1.0, scan, u.scanline_strength);
|
||||
// Scanlines — 1 pixel físico oscuro por fila lógica.
|
||||
// Usa uv.y (independiente del offset de letterbox) con pixel_scale para
|
||||
// calcular la posición dentro de la fila en coordenadas físicas.
|
||||
// 3x: 1 dark + 2 bright. 4x: 1 dark + 3 bright.
|
||||
// bright=3.5×, dark floor=0.42 (mantiene aspecto CRT original).
|
||||
if (u.scanline_strength > 0.0) {
|
||||
float ps = max(1.0, round(u.pixel_scale));
|
||||
float frac_in_row = fract(uv.y * u.screen_height);
|
||||
float row_pos = floor(frac_in_row * ps);
|
||||
float is_dark = step(ps - 1.0, row_pos);
|
||||
float scan = mix(3.5, 0.42, is_dark);
|
||||
colour *= mix(1.0, scan, u.scanline_strength);
|
||||
}
|
||||
|
||||
if (u.gamma_strength > 0.0) {
|
||||
vec3 enc = pow(colour, vec3(1.0 / 2.2));
|
||||
@@ -109,7 +120,8 @@ void main() {
|
||||
float vignette = 1.0 - dot(d, d) * u.vignette_strength;
|
||||
colour *= clamp(vignette, 0.0, 1.0);
|
||||
|
||||
// Máscara de fósforo RGB
|
||||
// Máscara de fósforo RGB — después de scanlines (orden original):
|
||||
// filas brillantes saturadas → máscara invisible, filas oscuras → RGB visible.
|
||||
if (u.mask_strength > 0.0) {
|
||||
float whichMask = fract(gl_FragCoord.x * 0.3333333);
|
||||
vec3 mask = vec3(0.80);
|
||||
@@ -122,5 +134,11 @@ void main() {
|
||||
colour = mix(colour, colour * mask, u.mask_strength);
|
||||
}
|
||||
|
||||
// Parpadeo de fósforo CRT (~50 Hz)
|
||||
if (u.flicker > 0.0) {
|
||||
float flicker_wave = sin(u.time * 100.0) * 0.5 + 0.5;
|
||||
colour *= 1.0 - u.flicker * 0.04 * flicker_wave;
|
||||
}
|
||||
|
||||
out_color = vec4(colour, 1.0);
|
||||
}
|
||||
|
||||
@@ -6,16 +6,13 @@
|
||||
#include <vector> // Para vector
|
||||
|
||||
#include "core/input/input.hpp" // Para Input, InputAction, Input::DO_NOT_ALLOW_REPEAT
|
||||
#include "core/locale/locale.hpp" // Para Locale
|
||||
#include "core/rendering/screen.hpp" // Para Screen
|
||||
#include "game/options.hpp" // Para Options, options, OptionsVideo, Section
|
||||
#include "game/scene_manager.hpp" // Para SceneManager
|
||||
#include "game/ui/notifier.hpp" // Para Notifier, NotificationText
|
||||
#include "utils/utils.hpp" // Para stringInVector
|
||||
|
||||
#ifdef _DEBUG
|
||||
#include "core/system/debug.hpp" // Para Debug
|
||||
#endif
|
||||
|
||||
namespace GlobalInputs {
|
||||
|
||||
// Funciones internas
|
||||
@@ -27,7 +24,7 @@ namespace GlobalInputs {
|
||||
if (stringInVector(Notifier::get()->getCodes(), CODE)) {
|
||||
SceneManager::current = SceneManager::Scene::TITLE;
|
||||
} else {
|
||||
Notifier::get()->show({CODE}, Notifier::Style::DEFAULT, -1, true, CODE);
|
||||
Notifier::get()->show({Locale::get()->get("ui.press_again_menu")}, Notifier::Style::DEFAULT, -1, true, CODE);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -47,7 +44,7 @@ namespace GlobalInputs {
|
||||
if (stringInVector(Notifier::get()->getCodes(), CODE)) {
|
||||
SceneManager::current = SceneManager::Scene::QUIT;
|
||||
} else {
|
||||
Notifier::get()->show({CODE}, Notifier::Style::DEFAULT, -1, true, CODE);
|
||||
Notifier::get()->show({Locale::get()->get("ui.press_again_exit")}, Notifier::Style::DEFAULT, -1, true, CODE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,72 +68,65 @@ namespace GlobalInputs {
|
||||
|
||||
void handleToggleBorder() {
|
||||
Screen::get()->toggleBorder();
|
||||
Notifier::get()->show({"BORDER " + std::string(Options::video.border.enabled ? "ENABLED" : "DISABLED")});
|
||||
Notifier::get()->show({Locale::get()->get(Options::video.border.enabled ? "ui.border_enabled" : "ui.border_disabled")});
|
||||
}
|
||||
|
||||
void handleToggleVideoMode() {
|
||||
Screen::get()->toggleVideoMode();
|
||||
Notifier::get()->show({"FULLSCREEN " + std::string(static_cast<int>(Options::video.fullscreen) == 0 ? "DISABLED" : "ENABLED")});
|
||||
Notifier::get()->show({Locale::get()->get(static_cast<int>(Options::video.fullscreen) == 0 ? "ui.fullscreen_disabled" : "ui.fullscreen_enabled")});
|
||||
}
|
||||
|
||||
void handleDecWindowZoom() {
|
||||
if (Screen::get()->decWindowZoom()) {
|
||||
Notifier::get()->show({"WINDOW ZOOM x" + std::to_string(Options::window.zoom)});
|
||||
Notifier::get()->show({Locale::get()->get("ui.window_zoom") + std::to_string(Options::window.zoom)});
|
||||
}
|
||||
}
|
||||
|
||||
void handleIncWindowZoom() {
|
||||
if (Screen::get()->incWindowZoom()) {
|
||||
Notifier::get()->show({"WINDOW ZOOM x" + std::to_string(Options::window.zoom)});
|
||||
Notifier::get()->show({Locale::get()->get("ui.window_zoom") + std::to_string(Options::window.zoom)});
|
||||
}
|
||||
}
|
||||
|
||||
void handleTogglePostFX() {
|
||||
Screen::get()->togglePostFX();
|
||||
Notifier::get()->show({"POSTFX " + std::string(Options::video.postfx ? "ENABLED" : "DISABLED")});
|
||||
Notifier::get()->show({Locale::get()->get(Options::video.postfx ? "ui.postfx_enabled" : "ui.postfx_disabled")});
|
||||
}
|
||||
|
||||
void handleToggleSupersampling() {
|
||||
Screen::get()->toggleSupersampling();
|
||||
Notifier::get()->show({Locale::get()->get(Options::video.supersampling ? "ui.supersampling_enabled" : "ui.supersampling_disabled")});
|
||||
}
|
||||
|
||||
void handleNextPostFXPreset() {
|
||||
if (!Options::postfx_presets.empty()) {
|
||||
Options::current_postfx_preset = (Options::current_postfx_preset + 1) % static_cast<int>(Options::postfx_presets.size());
|
||||
Screen::get()->reloadPostFX();
|
||||
Notifier::get()->show({"POSTFX " + Options::postfx_presets[static_cast<size_t>(Options::current_postfx_preset)].name});
|
||||
Notifier::get()->show({Locale::get()->get("ui.postfx") + " " + Options::postfx_presets[static_cast<size_t>(Options::current_postfx_preset)].name});
|
||||
}
|
||||
}
|
||||
|
||||
void handleNextPalette() {
|
||||
Screen::get()->nextPalette();
|
||||
Notifier::get()->show({"PALETTE " + Options::video.palette});
|
||||
Notifier::get()->show({Locale::get()->get("ui.palette") + " " + Options::video.palette});
|
||||
}
|
||||
|
||||
void handlePreviousPalette() {
|
||||
Screen::get()->previousPalette();
|
||||
Notifier::get()->show({"PALETTE " + Options::video.palette});
|
||||
Notifier::get()->show({Locale::get()->get("ui.palette") + " " + Options::video.palette});
|
||||
}
|
||||
|
||||
void handleToggleIntegerScale() {
|
||||
Screen::get()->toggleIntegerScale();
|
||||
Screen::get()->setVideoMode(Options::video.fullscreen);
|
||||
Notifier::get()->show({"INTEGER SCALE " + std::string(Options::video.integer_scale ? "ENABLED" : "DISABLED")});
|
||||
Notifier::get()->show({Locale::get()->get(Options::video.integer_scale ? "ui.integer_scale_enabled" : "ui.integer_scale_disabled")});
|
||||
}
|
||||
|
||||
void handleToggleVSync() {
|
||||
Screen::get()->toggleVSync();
|
||||
Notifier::get()->show({"V-SYNC " + std::string(Options::video.vertical_sync ? "ENABLED" : "DISABLED")});
|
||||
Notifier::get()->show({Locale::get()->get(Options::video.vertical_sync ? "ui.vsync_enabled" : "ui.vsync_disabled")});
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
void handleShowDebugInfo() {
|
||||
Screen::get()->toggleDebugInfo();
|
||||
}
|
||||
|
||||
/*
|
||||
void handleToggleDebug() {
|
||||
Debug::get()->toggleEnabled();
|
||||
Notifier::get()->show({"DEBUG " + std::string(Debug::get()->isEnabled() ? "ENABLED" : "DISABLED")}, Notifier::TextAlign::CENTER);
|
||||
}
|
||||
*/
|
||||
#endif
|
||||
|
||||
// Detecta qué acción global ha sido presionada (si alguna)
|
||||
auto getPressedAction() -> InputAction {
|
||||
@@ -161,10 +151,13 @@ void handleToggleDebug() {
|
||||
}
|
||||
}
|
||||
if (Input::get()->checkAction(InputAction::TOGGLE_POSTFX, Input::DO_NOT_ALLOW_REPEAT)) {
|
||||
if (Options::video.postfx && ((SDL_GetModState() & SDL_KMOD_SHIFT) != 0U)) {
|
||||
return InputAction::NEXT_POSTFX_PRESET;
|
||||
if ((SDL_GetModState() & SDL_KMOD_CTRL) != 0U) {
|
||||
return InputAction::TOGGLE_SUPERSAMPLING; // Ctrl+F4
|
||||
}
|
||||
return InputAction::TOGGLE_POSTFX;
|
||||
if (Options::video.postfx && ((SDL_GetModState() & SDL_KMOD_SHIFT) != 0U)) {
|
||||
return InputAction::NEXT_POSTFX_PRESET; // Shift+F4
|
||||
}
|
||||
return InputAction::TOGGLE_POSTFX; // F4
|
||||
}
|
||||
if (Input::get()->checkAction(InputAction::NEXT_PALETTE, Input::DO_NOT_ALLOW_REPEAT)) {
|
||||
return InputAction::NEXT_PALETTE;
|
||||
@@ -240,6 +233,10 @@ void handleToggleDebug() {
|
||||
handleNextPostFXPreset();
|
||||
break;
|
||||
|
||||
case InputAction::TOGGLE_SUPERSAMPLING:
|
||||
handleToggleSupersampling();
|
||||
break;
|
||||
|
||||
case InputAction::NEXT_PALETTE:
|
||||
handleNextPalette();
|
||||
break;
|
||||
@@ -256,13 +253,12 @@ void handleToggleDebug() {
|
||||
handleToggleVSync();
|
||||
break;
|
||||
|
||||
#ifdef _DEBUG
|
||||
case InputAction::TOGGLE_DEBUG:
|
||||
// handleToggleDebug();
|
||||
Screen::get()->toggleFPS();
|
||||
break;
|
||||
|
||||
#ifdef _DEBUG
|
||||
case InputAction::SHOW_DEBUG_INFO:
|
||||
handleShowDebugInfo();
|
||||
break;
|
||||
#endif
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ enum class InputAction : int { // Acciones de entrada posibles en el juego
|
||||
TOGGLE_INTEGER_SCALE,
|
||||
TOGGLE_POSTFX,
|
||||
NEXT_POSTFX_PRESET,
|
||||
TOGGLE_SUPERSAMPLING,
|
||||
TOGGLE_BORDER,
|
||||
TOGGLE_MUSIC,
|
||||
NEXT_PALETTE,
|
||||
|
||||
90
source/core/locale/locale.cpp
Normal file
@@ -0,0 +1,90 @@
|
||||
#include "core/locale/locale.hpp"
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "external/fkyaml_node.hpp" // Para fkyaml::node
|
||||
#include "game/options.hpp" // Para Options::console
|
||||
|
||||
// [SINGLETON]
|
||||
Locale* Locale::instance = nullptr;
|
||||
|
||||
// [SINGLETON] Crea el objeto con esta función estática
|
||||
void Locale::init(const std::string& file_path) {
|
||||
Locale::instance = new Locale();
|
||||
Locale::instance->loadFromFile(file_path);
|
||||
}
|
||||
|
||||
// [SINGLETON] Destruye el objeto con esta función estática
|
||||
void Locale::destroy() {
|
||||
delete Locale::instance;
|
||||
Locale::instance = nullptr;
|
||||
}
|
||||
|
||||
// [SINGLETON] Con este método obtenemos el objeto y podemos trabajar con él
|
||||
auto Locale::get() -> Locale* {
|
||||
return Locale::instance;
|
||||
}
|
||||
|
||||
// Devuelve la traducción de la clave o la clave como fallback
|
||||
auto Locale::get(const std::string& key) const -> std::string {
|
||||
auto it = strings_.find(key);
|
||||
if (it != strings_.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
if (Options::console) {
|
||||
std::cerr << "Locale: clave no encontrada: " << key << '\n';
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
// Aplana un nodo YAML de forma recursiva: {a: {b: "val"}} -> {"a.b" -> "val"}
|
||||
void Locale::flatten(const void* node_ptr, const std::string& prefix) {
|
||||
const auto& node = *static_cast<const fkyaml::node*>(node_ptr);
|
||||
|
||||
for (auto itr = node.begin(); itr != node.end(); ++itr) {
|
||||
const std::string KEY = prefix.empty()
|
||||
? itr.key().get_value<std::string>()
|
||||
: prefix + "." + itr.key().get_value<std::string>();
|
||||
|
||||
const auto& value = itr.value();
|
||||
if (value.is_mapping()) {
|
||||
flatten(&value, KEY);
|
||||
} else if (value.is_string()) {
|
||||
strings_[KEY] = value.get_value<std::string>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Carga las traducciones desde el fichero YAML indicado
|
||||
void Locale::loadFromFile(const std::string& file_path) {
|
||||
if (file_path.empty()) {
|
||||
if (Options::console) {
|
||||
std::cerr << "Locale: ruta de fichero vacía, sin traducciones cargadas\n";
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
std::ifstream file(file_path);
|
||||
if (!file.is_open()) {
|
||||
if (Options::console) {
|
||||
std::cerr << "Locale: no se puede abrir " << file_path << '\n';
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
auto yaml = fkyaml::node::deserialize(file);
|
||||
flatten(&yaml, "");
|
||||
|
||||
if (Options::console) {
|
||||
std::cout << "Locale: " << strings_.size() << " traducciones cargadas desde " << file_path << '\n';
|
||||
}
|
||||
} catch (const fkyaml::exception& e) {
|
||||
if (Options::console) {
|
||||
std::cerr << "Locale: error al parsear YAML: " << e.what() << '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
26
source/core/locale/locale.hpp
Normal file
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
// Clase Locale: gestiona las traducciones del juego (singleton)
|
||||
// Las traducciones se cargan desde un fichero YAML en el inicio.
|
||||
// No se permite cambio de idioma en caliente.
|
||||
class Locale {
|
||||
public:
|
||||
static void init(const std::string& file_path); // Crea e inicializa el singleton
|
||||
static void destroy(); // Destruye el singleton
|
||||
static auto get() -> Locale*; // Devuelve el singleton
|
||||
|
||||
// Devuelve la traducción de la clave dada.
|
||||
// Si la clave no existe, devuelve la propia clave como fallback.
|
||||
[[nodiscard]] auto get(const std::string& key) const -> std::string;
|
||||
|
||||
private:
|
||||
Locale() = default;
|
||||
void loadFromFile(const std::string& file_path);
|
||||
void flatten(const void* node_ptr, const std::string& prefix); // Aplana nodos YAML anidados
|
||||
|
||||
static Locale* instance;
|
||||
std::unordered_map<std::string, std::string> strings_;
|
||||
};
|
||||
@@ -393,7 +393,7 @@ auto Screen::findPalette(const std::string& name) -> size_t {
|
||||
|
||||
// Muestra información por pantalla
|
||||
void Screen::renderInfo() const {
|
||||
if (show_debug_info_ && (Resource::Cache::get() != nullptr)) {
|
||||
if (show_fps_ && (Resource::Cache::get() != nullptr)) {
|
||||
auto text = Resource::Cache::get()->getText("smb2");
|
||||
auto color = static_cast<Uint8>(PaletteColor::YELLOW);
|
||||
auto shadow = static_cast<Uint8>(PaletteColor::BLACK);
|
||||
@@ -428,8 +428,8 @@ void Screen::hide() { SDL_HideWindow(window_); }
|
||||
// Establece la visibilidad de las notificaciones
|
||||
void Screen::setNotificationsEnabled(bool value) { notifications_enabled_ = value; }
|
||||
|
||||
// Activa / desactiva la información de debug
|
||||
void Screen::toggleDebugInfo() { show_debug_info_ = !show_debug_info_; }
|
||||
// Activa / desactiva el contador de FPS
|
||||
void Screen::toggleFPS() { show_fps_ = !show_fps_; }
|
||||
|
||||
// Alterna entre activar y desactivar el escalado entero
|
||||
void Screen::toggleIntegerScale() {
|
||||
@@ -459,11 +459,23 @@ auto loadData(const std::string& filepath) -> std::vector<uint8_t> {
|
||||
return Resource::Helper::loadFile(filepath);
|
||||
}
|
||||
|
||||
// Activa/desactiva el supersampling global (Ctrl+F4)
|
||||
void Screen::toggleSupersampling() {
|
||||
Options::video.supersampling = !Options::video.supersampling;
|
||||
if (Options::video.postfx && shader_backend_ && shader_backend_->isHardwareAccelerated()) {
|
||||
applyCurrentPostFXPreset();
|
||||
}
|
||||
}
|
||||
|
||||
// Aplica los parámetros del preset actual al backend de shaders
|
||||
void Screen::applyCurrentPostFXPreset() {
|
||||
if (shader_backend_ && !Options::postfx_presets.empty()) {
|
||||
const auto& p = Options::postfx_presets[static_cast<size_t>(Options::current_postfx_preset)];
|
||||
Rendering::PostFXParams params{.vignette = p.vignette, .scanlines = p.scanlines, .chroma = p.chroma, .mask = p.mask, .gamma = p.gamma, .curvature = p.curvature, .bleeding = p.bleeding};
|
||||
// Supersampling es un toggle global (Options::video.supersampling), no por preset.
|
||||
// setOversample primero: puede recrear texturas antes de que setPostFXParams
|
||||
// decida si hornear scanlines en CPU o aplicarlas en GPU.
|
||||
shader_backend_->setOversample(Options::video.supersampling ? 3 : 1);
|
||||
Rendering::PostFXParams params{.vignette = p.vignette, .scanlines = p.scanlines, .chroma = p.chroma, .mask = p.mask, .gamma = p.gamma, .curvature = p.curvature, .bleeding = p.bleeding, .flicker = p.flicker};
|
||||
shader_backend_->setPostFXParams(params);
|
||||
}
|
||||
}
|
||||
@@ -602,5 +614,5 @@ void Screen::createText() {
|
||||
auto surface = std::make_shared<Surface>(Resource::List::get()->get("aseprite.gif"));
|
||||
|
||||
// Crea el objeto de texto (el constructor de Text carga el archivo text_file internamente)
|
||||
text_ = std::make_shared<Text>(surface, Resource::List::get()->get("aseprite.txt"));
|
||||
text_ = std::make_shared<Text>(surface, Resource::List::get()->get("aseprite.fnt"));
|
||||
}
|
||||
@@ -56,13 +56,14 @@ class Screen {
|
||||
void nextPalette(); // Cambia a la siguiente paleta
|
||||
void previousPalette(); // Cambia a la paleta anterior
|
||||
void setPalete(); // Establece la paleta actual
|
||||
void togglePostFX(); // Cambia el estado del PostFX
|
||||
void reloadPostFX(); // Recarga el shader del preset actual sin toggle
|
||||
void togglePostFX(); // Cambia el estado del PostFX
|
||||
void toggleSupersampling(); // Activa/desactiva el supersampling global
|
||||
void reloadPostFX(); // Recarga el shader del preset actual sin toggle
|
||||
|
||||
// Surfaces y notificaciones
|
||||
void setRendererSurface(const std::shared_ptr<Surface>& surface = nullptr); // Establece el renderizador para las surfaces
|
||||
void setNotificationsEnabled(bool value); // Establece la visibilidad de las notificaciones
|
||||
void toggleDebugInfo(); // Activa o desactiva la información de debug
|
||||
void toggleFPS(); // Activa o desactiva el contador de FPS
|
||||
|
||||
// Getters
|
||||
auto getRenderer() -> SDL_Renderer*;
|
||||
@@ -158,8 +159,8 @@ class Screen {
|
||||
std::vector<Uint32> pixel_buffer_; // Buffer intermedio para SDL3GPU path (surface → ARGB)
|
||||
|
||||
#ifdef _DEBUG
|
||||
bool show_debug_info_{true}; // Indica si ha de mostrar la información de debug
|
||||
bool show_fps_{true}; // Indica si ha de mostrar el contador de FPS
|
||||
#else
|
||||
bool show_debug_info_{false}; // Indica si ha de mostrar la información de debug
|
||||
bool show_fps_{false}; // Indica si ha de mostrar el contador de FPS
|
||||
#endif
|
||||
};
|
||||
@@ -54,6 +54,10 @@ struct PostFXUniforms {
|
||||
float gamma_strength;
|
||||
float curvature;
|
||||
float bleeding;
|
||||
float pixel_scale;
|
||||
float time;
|
||||
float oversample; // 1.0 = sin SS, 3.0 = 3× supersampling
|
||||
float flicker; // 0 = off, 1 = phosphor flicker ~50 Hz
|
||||
};
|
||||
|
||||
// YCbCr helpers for NTSC bleeding
|
||||
@@ -98,23 +102,25 @@ fragment float4 postfx_fs(PostVOut in [[stage_in]],
|
||||
// Muestra base
|
||||
float3 base = scene.sample(samp, uv).rgb;
|
||||
|
||||
// Sangrado NTSC — difuminado horizontal de crominancia
|
||||
// Sangrado NTSC — difuminado horizontal de crominancia.
|
||||
// step = 1 pixel de juego en espacio UV (corrige SS: scene.get_width() = game_w * oversample).
|
||||
float3 colour;
|
||||
if (u.bleeding > 0.0f) {
|
||||
float tw = float(scene.get_width());
|
||||
float3 ycc = rgb_to_ycc(base);
|
||||
float3 ycc_l2 = rgb_to_ycc(scene.sample(samp, uv - float2(2.0f/tw, 0.0f)).rgb);
|
||||
float3 ycc_l1 = rgb_to_ycc(scene.sample(samp, uv - float2(1.0f/tw, 0.0f)).rgb);
|
||||
float3 ycc_r1 = rgb_to_ycc(scene.sample(samp, uv + float2(1.0f/tw, 0.0f)).rgb);
|
||||
float3 ycc_r2 = rgb_to_ycc(scene.sample(samp, uv + float2(2.0f/tw, 0.0f)).rgb);
|
||||
float tw = float(scene.get_width());
|
||||
float step = u.oversample / tw; // 1 pixel lógico en UV
|
||||
float3 ycc = rgb_to_ycc(base);
|
||||
float3 ycc_l2 = rgb_to_ycc(scene.sample(samp, uv - float2(2.0f*step, 0.0f)).rgb);
|
||||
float3 ycc_l1 = rgb_to_ycc(scene.sample(samp, uv - float2(1.0f*step, 0.0f)).rgb);
|
||||
float3 ycc_r1 = rgb_to_ycc(scene.sample(samp, uv + float2(1.0f*step, 0.0f)).rgb);
|
||||
float3 ycc_r2 = rgb_to_ycc(scene.sample(samp, uv + float2(2.0f*step, 0.0f)).rgb);
|
||||
ycc.yz = (ycc_l2.yz + ycc_l1.yz*2.0f + ycc.yz*2.0f + ycc_r1.yz*2.0f + ycc_r2.yz) / 8.0f;
|
||||
colour = mix(base, ycc_to_rgb(ycc), u.bleeding);
|
||||
} else {
|
||||
colour = base;
|
||||
}
|
||||
|
||||
// Aberración cromática
|
||||
float ca = u.chroma_strength * 0.005f;
|
||||
// Aberración cromática (drift animado con time para efecto NTSC real)
|
||||
float ca = u.chroma_strength * 0.005f * (1.0f + 0.15f * sin(u.time * 7.3f));
|
||||
colour.r = scene.sample(samp, uv + float2(ca, 0.0f)).r;
|
||||
colour.b = scene.sample(samp, uv - float2(ca, 0.0f)).b;
|
||||
|
||||
@@ -124,14 +130,19 @@ fragment float4 postfx_fs(PostVOut in [[stage_in]],
|
||||
colour = mix(colour, lin, u.gamma_strength);
|
||||
}
|
||||
|
||||
// Scanlines
|
||||
float texHeight = float(scene.get_height());
|
||||
float scaleY = u.screen_height / texHeight;
|
||||
float screenY = uv.y * u.screen_height;
|
||||
float posInRow = fmod(screenY, scaleY);
|
||||
float scanLineDY = posInRow / scaleY - 0.5f;
|
||||
float scan = max(1.0f - scanLineDY * scanLineDY * 6.0f, 0.12f) * 3.5f;
|
||||
colour *= mix(1.0f, scan, u.scanline_strength);
|
||||
// Scanlines — 1 pixel físico oscuro por fila lógica.
|
||||
// Usa uv.y (independiente del offset de letterbox) con pixel_scale para
|
||||
// calcular la posición dentro de la fila en coordenadas físicas.
|
||||
// 3x: 1 dark + 2 bright. 4x: 1 dark + 3 bright.
|
||||
// bright=3.5×, dark floor=0.42 (mantiene aspecto CRT original).
|
||||
if (u.scanline_strength > 0.0f) {
|
||||
float ps = max(1.0f, round(u.pixel_scale));
|
||||
float frac_in_row = fract(uv.y * u.screen_height);
|
||||
float row_pos = floor(frac_in_row * ps);
|
||||
float is_dark = step(ps - 1.0f, row_pos);
|
||||
float scan = mix(3.5f, 0.42f, is_dark);
|
||||
colour *= mix(1.0f, scan, u.scanline_strength);
|
||||
}
|
||||
|
||||
if (u.gamma_strength > 0.0f) {
|
||||
float3 enc = pow(colour, float3(1.0f/2.2f));
|
||||
@@ -143,7 +154,8 @@ fragment float4 postfx_fs(PostVOut in [[stage_in]],
|
||||
float vignette = 1.0f - dot(d, d) * u.vignette_strength;
|
||||
colour *= clamp(vignette, 0.0f, 1.0f);
|
||||
|
||||
// Máscara de fósforo RGB
|
||||
// Máscara de fósforo RGB — después de scanlines (orden original):
|
||||
// filas brillantes saturadas → máscara invisible, filas oscuras → RGB visible.
|
||||
if (u.mask_strength > 0.0f) {
|
||||
float whichMask = fract(in.pos.x * 0.3333333f);
|
||||
float3 mask = float3(0.80f);
|
||||
@@ -153,6 +165,12 @@ fragment float4 postfx_fs(PostVOut in [[stage_in]],
|
||||
colour = mix(colour, colour * mask, u.mask_strength);
|
||||
}
|
||||
|
||||
// Parpadeo de fósforo CRT (~50 Hz)
|
||||
if (u.flicker > 0.0f) {
|
||||
float flicker_wave = sin(u.time * 100.0f) * 0.5f + 0.5f;
|
||||
colour *= 1.0f - u.flicker * 0.04f * flicker_wave;
|
||||
}
|
||||
|
||||
return float4(colour, 1.0f);
|
||||
}
|
||||
)";
|
||||
@@ -189,9 +207,12 @@ namespace Rendering {
|
||||
float fw = 0.0F;
|
||||
float fh = 0.0F;
|
||||
SDL_GetTextureSize(texture, &fw, &fh);
|
||||
tex_width_ = static_cast<int>(fw);
|
||||
tex_height_ = static_cast<int>(fh);
|
||||
uniforms_.screen_height = fh; // Altura lógica del juego (no el swapchain físico)
|
||||
game_width_ = static_cast<int>(fw);
|
||||
game_height_ = static_cast<int>(fh);
|
||||
tex_width_ = game_width_ * oversample_;
|
||||
tex_height_ = game_height_ * oversample_;
|
||||
uniforms_.screen_height = static_cast<float>(tex_height_); // Altura de la textura GPU
|
||||
uniforms_.oversample = static_cast<float>(oversample_);
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// 1. Create GPU device (solo si no existe ya)
|
||||
@@ -254,7 +275,7 @@ namespace Rendering {
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// 5. Create nearest-neighbour sampler (retro pixel art)
|
||||
// 5. Create samplers: NEAREST (pixel art) + LINEAR (supersampling)
|
||||
// ----------------------------------------------------------------
|
||||
SDL_GPUSamplerCreateInfo samp_info = {};
|
||||
samp_info.min_filter = SDL_GPU_FILTER_NEAREST;
|
||||
@@ -270,6 +291,20 @@ namespace Rendering {
|
||||
return false;
|
||||
}
|
||||
|
||||
SDL_GPUSamplerCreateInfo lsamp_info = {};
|
||||
lsamp_info.min_filter = SDL_GPU_FILTER_LINEAR;
|
||||
lsamp_info.mag_filter = SDL_GPU_FILTER_LINEAR;
|
||||
lsamp_info.mipmap_mode = SDL_GPU_SAMPLERMIPMAPMODE_NEAREST;
|
||||
lsamp_info.address_mode_u = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE;
|
||||
lsamp_info.address_mode_v = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE;
|
||||
lsamp_info.address_mode_w = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE;
|
||||
linear_sampler_ = SDL_CreateGPUSampler(device_, &lsamp_info);
|
||||
if (linear_sampler_ == nullptr) {
|
||||
SDL_Log("SDL3GPUShader: failed to create linear sampler: %s", SDL_GetError());
|
||||
cleanup();
|
||||
return false;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// 6. Create PostFX graphics pipeline
|
||||
// ----------------------------------------------------------------
|
||||
@@ -335,7 +370,9 @@ namespace Rendering {
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// uploadPixels — copies ARGB8888 CPU pixels into the GPU transfer buffer
|
||||
// uploadPixels — copies ARGB8888 CPU pixels into the GPU transfer buffer.
|
||||
// Con supersampling (oversample_ > 1) expande cada pixel del juego a un bloque
|
||||
// oversample × oversample y hornea la scanline oscura en la última fila del bloque.
|
||||
// ---------------------------------------------------------------------------
|
||||
void SDL3GPUShader::uploadPixels(const Uint32* pixels, int width, int height) {
|
||||
if (!is_initialized_ || (upload_buffer_ == nullptr)) { return; }
|
||||
@@ -345,7 +382,45 @@ namespace Rendering {
|
||||
SDL_Log("SDL3GPUShader: SDL_MapGPUTransferBuffer failed: %s", SDL_GetError());
|
||||
return;
|
||||
}
|
||||
std::memcpy(mapped, pixels, static_cast<size_t>(width * height * 4));
|
||||
|
||||
if (oversample_ <= 1) {
|
||||
// Path sin supersampling: copia directa
|
||||
std::memcpy(mapped, pixels, static_cast<size_t>(width * height * 4));
|
||||
} else {
|
||||
// Path con supersampling: expande cada pixel a OS×OS, oscurece última fila.
|
||||
// Replica la fórmula del shader: mix(3.5, 0.42, scanline_strength).
|
||||
auto* out = static_cast<Uint32*>(mapped);
|
||||
const int OS = oversample_;
|
||||
const float BRIGHT_MUL = 1.0F + (baked_scanline_strength_ * 2.5F); // rows 0..OS-2
|
||||
const float DARK_MUL = 1.0F - (baked_scanline_strength_ * 0.58F); // row OS-1
|
||||
|
||||
for (int y = 0; y < height; ++y) {
|
||||
for (int x = 0; x < width; ++x) {
|
||||
const Uint32 SRC = pixels[y * width + x];
|
||||
const Uint32 ALPHA = (SRC >> 24) & 0xFFU;
|
||||
const auto FR = static_cast<float>((SRC >> 16) & 0xFFU);
|
||||
const auto FG = static_cast<float>((SRC >> 8) & 0xFFU);
|
||||
const auto FB = static_cast<float>( SRC & 0xFFU);
|
||||
|
||||
auto make_px = [ALPHA](float rv, float gv, float bv) -> Uint32 {
|
||||
auto cl = [](float v) -> Uint32 { return static_cast<Uint32>(std::min(255.0F, v)); };
|
||||
return (ALPHA << 24) | (cl(rv) << 16) | (cl(gv) << 8) | cl(bv);
|
||||
};
|
||||
|
||||
const Uint32 BRIGHT = make_px(FR * BRIGHT_MUL, FG * BRIGHT_MUL, FB * BRIGHT_MUL);
|
||||
const Uint32 DARK = make_px(FR * DARK_MUL, FG * DARK_MUL, FB * DARK_MUL);
|
||||
|
||||
for (int dy = 0; dy < OS; ++dy) {
|
||||
const Uint32 OUT_PX = (dy == OS - 1) ? DARK : BRIGHT;
|
||||
const int DST_Y = (y * OS) + dy;
|
||||
for (int dx = 0; dx < OS; ++dx) {
|
||||
out[DST_Y * (width * OS) + (x * OS) + dx] = OUT_PX;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SDL_UnmapGPUTransferBuffer(device_, upload_buffer_);
|
||||
}
|
||||
|
||||
@@ -406,30 +481,45 @@ namespace Rendering {
|
||||
if (pass != nullptr) {
|
||||
SDL_BindGPUGraphicsPipeline(pass, pipeline_);
|
||||
|
||||
// Calcular viewport para mantener relación de aspecto (letterbox o integer scale)
|
||||
// Calcular viewport usando las dimensiones lógicas del canvas (game_width_/height_),
|
||||
// no las de la textura GPU (que pueden ser game×3 con supersampling).
|
||||
// El GPU escala la textura para cubrir el viewport independientemente de su resolución.
|
||||
float vx = 0.0F;
|
||||
float vy = 0.0F;
|
||||
float vw = 0.0F;
|
||||
float vh = 0.0F;
|
||||
if (integer_scale_) {
|
||||
const int SCALE = std::max(1, std::min(static_cast<int>(sw) / tex_width_, static_cast<int>(sh) / tex_height_));
|
||||
vw = static_cast<float>(tex_width_ * SCALE);
|
||||
vh = static_cast<float>(tex_height_ * SCALE);
|
||||
const int SCALE = std::max(1, std::min(static_cast<int>(sw) / game_width_, static_cast<int>(sh) / game_height_));
|
||||
vw = static_cast<float>(game_width_ * SCALE);
|
||||
vh = static_cast<float>(game_height_ * SCALE);
|
||||
} else {
|
||||
const float SCALE = std::min(
|
||||
static_cast<float>(sw) / static_cast<float>(tex_width_),
|
||||
static_cast<float>(sh) / static_cast<float>(tex_height_));
|
||||
vw = static_cast<float>(tex_width_) * SCALE;
|
||||
vh = static_cast<float>(tex_height_) * SCALE;
|
||||
static_cast<float>(sw) / static_cast<float>(game_width_),
|
||||
static_cast<float>(sh) / static_cast<float>(game_height_));
|
||||
vw = static_cast<float>(game_width_) * SCALE;
|
||||
vh = static_cast<float>(game_height_) * SCALE;
|
||||
}
|
||||
vx = std::floor((static_cast<float>(sw) - vw) * 0.5F);
|
||||
vy = std::floor((static_cast<float>(sh) - vh) * 0.5F);
|
||||
SDL_GPUViewport vp = {vx, vy, vw, vh, 0.0F, 1.0F};
|
||||
SDL_SetGPUViewport(pass, &vp);
|
||||
|
||||
// pixel_scale: pixels físicos por pixel lógico de juego (para scanlines sin SS).
|
||||
// Con SS las scanlines están horneadas en CPU → scanline_strength=0 → no se usa.
|
||||
uniforms_.pixel_scale = (game_height_ > 0)
|
||||
? (vh / static_cast<float>(game_height_))
|
||||
: 1.0F;
|
||||
uniforms_.time = static_cast<float>(SDL_GetTicks()) / 1000.0F;
|
||||
uniforms_.oversample = static_cast<float>(oversample_);
|
||||
|
||||
// Con supersampling usamos LINEAR para que el escalado a zooms no-múltiplo-de-3
|
||||
// promedia correctamente las filas de scanline horneadas en CPU.
|
||||
SDL_GPUSampler* active_sampler = (oversample_ > 1 && linear_sampler_ != nullptr)
|
||||
? linear_sampler_ : sampler_;
|
||||
|
||||
SDL_GPUTextureSamplerBinding binding = {};
|
||||
binding.texture = scene_texture_;
|
||||
binding.sampler = sampler_;
|
||||
binding.sampler = active_sampler;
|
||||
SDL_BindGPUFragmentSamplers(pass, 0, &binding, 1);
|
||||
|
||||
SDL_PushGPUFragmentUniformData(cmd, 0, &uniforms_, sizeof(PostFXUniforms));
|
||||
@@ -466,6 +556,10 @@ namespace Rendering {
|
||||
SDL_ReleaseGPUSampler(device_, sampler_);
|
||||
sampler_ = nullptr;
|
||||
}
|
||||
if (linear_sampler_ != nullptr) {
|
||||
SDL_ReleaseGPUSampler(device_, linear_sampler_);
|
||||
linear_sampler_ = nullptr;
|
||||
}
|
||||
// device_ y el claim de la ventana se mantienen vivos
|
||||
}
|
||||
}
|
||||
@@ -534,12 +628,17 @@ namespace Rendering {
|
||||
|
||||
void SDL3GPUShader::setPostFXParams(const PostFXParams& p) {
|
||||
uniforms_.vignette_strength = p.vignette;
|
||||
uniforms_.scanline_strength = p.scanlines;
|
||||
uniforms_.chroma_strength = p.chroma;
|
||||
uniforms_.mask_strength = p.mask;
|
||||
uniforms_.gamma_strength = p.gamma;
|
||||
uniforms_.curvature = p.curvature;
|
||||
uniforms_.bleeding = p.bleeding;
|
||||
uniforms_.chroma_strength = p.chroma;
|
||||
uniforms_.mask_strength = p.mask;
|
||||
uniforms_.gamma_strength = p.gamma;
|
||||
uniforms_.curvature = p.curvature;
|
||||
uniforms_.bleeding = p.bleeding;
|
||||
uniforms_.flicker = p.flicker;
|
||||
|
||||
// Con supersampling las scanlines se hornean en CPU (uploadPixels).
|
||||
// El shader recibe strength=0 para no aplicarlas de nuevo en GPU.
|
||||
baked_scanline_strength_ = p.scanlines;
|
||||
uniforms_.scanline_strength = (oversample_ > 1) ? 0.0F : p.scanlines;
|
||||
}
|
||||
|
||||
void SDL3GPUShader::setVSync(bool vsync) {
|
||||
@@ -553,4 +652,68 @@ namespace Rendering {
|
||||
integer_scale_ = integer_scale;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// setOversample — cambia el factor SS; recrea texturas si ya está inicializado
|
||||
// ---------------------------------------------------------------------------
|
||||
void SDL3GPUShader::setOversample(int factor) {
|
||||
const int NEW_FACTOR = std::max(1, factor);
|
||||
if (NEW_FACTOR == oversample_) { return; }
|
||||
oversample_ = NEW_FACTOR;
|
||||
if (is_initialized_) {
|
||||
reinitTexturesAndBuffer();
|
||||
// scanline_strength se actualizará en el próximo setPostFXParams
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// reinitTexturesAndBuffer — recrea scene_texture_ y upload_buffer_ con el
|
||||
// tamaño actual (game × oversample_). No toca pipeline ni samplers.
|
||||
// ---------------------------------------------------------------------------
|
||||
auto SDL3GPUShader::reinitTexturesAndBuffer() -> bool {
|
||||
if (device_ == nullptr) { return false; }
|
||||
SDL_WaitForGPUIdle(device_);
|
||||
|
||||
if (scene_texture_ != nullptr) {
|
||||
SDL_ReleaseGPUTexture(device_, scene_texture_);
|
||||
scene_texture_ = nullptr;
|
||||
}
|
||||
if (upload_buffer_ != nullptr) {
|
||||
SDL_ReleaseGPUTransferBuffer(device_, upload_buffer_);
|
||||
upload_buffer_ = nullptr;
|
||||
}
|
||||
|
||||
tex_width_ = game_width_ * oversample_;
|
||||
tex_height_ = game_height_ * oversample_;
|
||||
uniforms_.screen_height = static_cast<float>(tex_height_);
|
||||
uniforms_.oversample = static_cast<float>(oversample_);
|
||||
|
||||
SDL_GPUTextureCreateInfo tex_info = {};
|
||||
tex_info.type = SDL_GPU_TEXTURETYPE_2D;
|
||||
tex_info.format = SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM;
|
||||
tex_info.usage = SDL_GPU_TEXTUREUSAGE_SAMPLER;
|
||||
tex_info.width = static_cast<Uint32>(tex_width_);
|
||||
tex_info.height = static_cast<Uint32>(tex_height_);
|
||||
tex_info.layer_count_or_depth = 1;
|
||||
tex_info.num_levels = 1;
|
||||
scene_texture_ = SDL_CreateGPUTexture(device_, &tex_info);
|
||||
if (scene_texture_ == nullptr) {
|
||||
SDL_Log("SDL3GPUShader: reinit — failed to create scene texture: %s", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
SDL_GPUTransferBufferCreateInfo tb_info = {};
|
||||
tb_info.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD;
|
||||
tb_info.size = static_cast<Uint32>(tex_width_ * tex_height_ * 4);
|
||||
upload_buffer_ = SDL_CreateGPUTransferBuffer(device_, &tb_info);
|
||||
if (upload_buffer_ == nullptr) {
|
||||
SDL_Log("SDL3GPUShader: reinit — failed to create upload buffer: %s", SDL_GetError());
|
||||
SDL_ReleaseGPUTexture(device_, scene_texture_);
|
||||
scene_texture_ = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
SDL_Log("SDL3GPUShader: oversample %d → texture %dx%d", oversample_, tex_width_, tex_height_);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Rendering
|
||||
|
||||
@@ -7,16 +7,20 @@
|
||||
|
||||
// PostFX uniforms pushed to fragment stage each frame.
|
||||
// Must match the MSL struct and GLSL uniform block layout.
|
||||
// 8 floats = 32 bytes — meets Metal/Vulkan 16-byte alignment requirement.
|
||||
// 12 floats = 48 bytes — meets Metal/Vulkan 16-byte alignment requirement.
|
||||
struct PostFXUniforms {
|
||||
float vignette_strength; // 0 = none, ~0.8 = subtle
|
||||
float chroma_strength; // 0 = off, ~0.2 = subtle chromatic aberration
|
||||
float scanline_strength; // 0 = off, 1 = full
|
||||
float screen_height; // logical height in pixels (for resolution-independent scanlines)
|
||||
float screen_height; // logical height in pixels (used by bleeding effect)
|
||||
float mask_strength; // 0 = off, 1 = full phosphor dot mask
|
||||
float gamma_strength; // 0 = off, 1 = full gamma 2.4/2.2 correction
|
||||
float curvature; // 0 = flat, 1 = max barrel distortion
|
||||
float bleeding; // 0 = off, 1 = max NTSC chrominance bleeding
|
||||
float pixel_scale; // physical pixels per logical pixel (vh / tex_height_)
|
||||
float time; // seconds since SDL init (SDL_GetTicks() / 1000.0f)
|
||||
float oversample; // supersampling factor (1.0 = off, 3.0 = 3×SS)
|
||||
float flicker; // 0 = off, 1 = phosphor flicker ~50 Hz — keep struct at 48 bytes (3 × 16)
|
||||
};
|
||||
|
||||
namespace Rendering {
|
||||
@@ -56,6 +60,9 @@ namespace Rendering {
|
||||
// Activa/desactiva escalado entero (integer scale)
|
||||
void setScaleMode(bool integer_scale) override;
|
||||
|
||||
// Establece factor de supersampling (1 = off, 3 = 3×SS)
|
||||
void setOversample(int factor) override;
|
||||
|
||||
private:
|
||||
static auto createShaderMSL(SDL_GPUDevice* device,
|
||||
const char* msl_source,
|
||||
@@ -73,18 +80,24 @@ namespace Rendering {
|
||||
Uint32 num_uniform_buffers) -> SDL_GPUShader*;
|
||||
|
||||
auto createPipeline() -> bool;
|
||||
auto reinitTexturesAndBuffer() -> bool; // Recrea textura y buffer con oversample actual
|
||||
|
||||
SDL_Window* window_ = nullptr;
|
||||
SDL_GPUDevice* device_ = nullptr;
|
||||
SDL_GPUGraphicsPipeline* pipeline_ = nullptr;
|
||||
SDL_GPUTexture* scene_texture_ = nullptr;
|
||||
SDL_GPUTransferBuffer* upload_buffer_ = nullptr;
|
||||
SDL_GPUSampler* sampler_ = nullptr;
|
||||
SDL_GPUSampler* sampler_ = nullptr; // NEAREST — para path sin supersampling
|
||||
SDL_GPUSampler* linear_sampler_ = nullptr; // LINEAR — para path con supersampling
|
||||
|
||||
PostFXUniforms uniforms_{.vignette_strength = 0.6F, .chroma_strength = 0.15F, .scanline_strength = 0.7F, .screen_height = 192.0F};
|
||||
PostFXUniforms uniforms_{.vignette_strength = 0.6F, .chroma_strength = 0.15F, .scanline_strength = 0.7F, .screen_height = 192.0F, .pixel_scale = 1.0F, .oversample = 1.0F};
|
||||
|
||||
int tex_width_ = 0;
|
||||
int game_width_ = 0; // Dimensiones originales del canvas (sin SS)
|
||||
int game_height_ = 0;
|
||||
int tex_width_ = 0; // Dimensiones de la textura GPU (game × oversample_)
|
||||
int tex_height_ = 0;
|
||||
int oversample_ = 1; // Factor SS actual (1 o 3)
|
||||
float baked_scanline_strength_ = 0.0F; // Guardado para hornear en CPU
|
||||
bool is_initialized_ = false;
|
||||
bool vsync_ = true;
|
||||
bool integer_scale_ = false;
|
||||
|
||||
@@ -11,13 +11,14 @@ namespace Rendering {
|
||||
* Definido a nivel de namespace para facilitar el uso desde subclases y screen.cpp
|
||||
*/
|
||||
struct PostFXParams {
|
||||
float vignette = 0.0F; // Intensidad de la viñeta
|
||||
float scanlines = 0.0F; // Intensidad de las scanlines
|
||||
float chroma = 0.0F; // Aberración cromática
|
||||
float mask = 0.0F; // Máscara de fósforo RGB
|
||||
float gamma = 0.0F; // Corrección gamma (blend 0=off, 1=full)
|
||||
float curvature = 0.0F; // Curvatura barrel CRT
|
||||
float bleeding = 0.0F; // Sangrado de color NTSC
|
||||
float vignette = 0.0F; // Intensidad de la viñeta
|
||||
float scanlines = 0.0F; // Intensidad de las scanlines
|
||||
float chroma = 0.0F; // Aberración cromática
|
||||
float mask = 0.0F; // Máscara de fósforo RGB
|
||||
float gamma = 0.0F; // Corrección gamma (blend 0=off, 1=full)
|
||||
float curvature = 0.0F; // Curvatura barrel CRT
|
||||
float bleeding = 0.0F; // Sangrado de color NTSC
|
||||
float flicker = 0.0F; // Parpadeo de fósforo CRT ~50 Hz
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -82,6 +83,13 @@ namespace Rendering {
|
||||
*/
|
||||
virtual void setScaleMode(bool /*integer_scale*/) {}
|
||||
|
||||
/**
|
||||
* @brief Establece el factor de supersampling (1 = off, 3 = 3× SS)
|
||||
* Con factor > 1, la textura GPU se crea a game×factor resolución y
|
||||
* las scanlines se hornean en CPU (uploadPixels). El sampler usa LINEAR.
|
||||
*/
|
||||
virtual void setOversample(int /*factor*/) {}
|
||||
|
||||
/**
|
||||
* @brief Verifica si el backend está usando aceleración por hardware
|
||||
* @return true si usa aceleración (OpenGL/Metal/Vulkan)
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include <cstddef> // Para size_t
|
||||
#include <fstream> // Para basic_ifstream, basic_istream, basic_ostream
|
||||
#include <iostream> // Para cerr
|
||||
#include <sstream> // Para istringstream
|
||||
#include <stdexcept> // Para runtime_error
|
||||
@@ -14,93 +13,119 @@
|
||||
#include "core/resources/resource_helper.hpp" // Para ResourceHelper
|
||||
#include "utils/utils.hpp" // Para getFileName, stringToColor, printWithDots
|
||||
|
||||
// Llena una estructuta TextFile desde un fichero
|
||||
// Extrae el siguiente codepoint UTF-8 de la cadena, avanzando 'pos' al byte siguiente
|
||||
auto Text::nextCodepoint(const std::string& s, size_t& pos) -> uint32_t {
|
||||
auto c = static_cast<unsigned char>(s[pos]);
|
||||
uint32_t cp = 0;
|
||||
size_t extra = 0;
|
||||
|
||||
if (c < 0x80) { cp = c; extra = 0; }
|
||||
else if (c < 0xC0) { pos++; return 0xFFFD; } // byte de continuación suelto
|
||||
else if (c < 0xE0) { cp = c & 0x1F; extra = 1; }
|
||||
else if (c < 0xF0) { cp = c & 0x0F; extra = 2; }
|
||||
else if (c < 0xF8) { cp = c & 0x07; extra = 3; }
|
||||
else { pos++; return 0xFFFD; }
|
||||
|
||||
pos++;
|
||||
for (size_t i = 0; i < extra && pos < s.size(); ++i, ++pos) {
|
||||
auto cb = static_cast<unsigned char>(s[pos]);
|
||||
if ((cb & 0xC0) != 0x80) { return 0xFFFD; }
|
||||
cp = (cp << 6) | (cb & 0x3F);
|
||||
}
|
||||
return cp;
|
||||
}
|
||||
|
||||
// Convierte un codepoint Unicode a una cadena UTF-8
|
||||
auto Text::codepointToUtf8(uint32_t cp) -> std::string {
|
||||
std::string result;
|
||||
if (cp < 0x80) {
|
||||
result += static_cast<char>(cp);
|
||||
} else if (cp < 0x800) {
|
||||
result += static_cast<char>(0xC0 | (cp >> 6));
|
||||
result += static_cast<char>(0x80 | (cp & 0x3F));
|
||||
} else if (cp < 0x10000) {
|
||||
result += static_cast<char>(0xE0 | (cp >> 12));
|
||||
result += static_cast<char>(0x80 | ((cp >> 6) & 0x3F));
|
||||
result += static_cast<char>(0x80 | (cp & 0x3F));
|
||||
} else {
|
||||
result += static_cast<char>(0xF0 | (cp >> 18));
|
||||
result += static_cast<char>(0x80 | ((cp >> 12) & 0x3F));
|
||||
result += static_cast<char>(0x80 | ((cp >> 6) & 0x3F));
|
||||
result += static_cast<char>(0x80 | (cp & 0x3F));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Carga un fichero de definición de fuente .fnt
|
||||
// Formato: líneas "clave valor", comentarios con #, gliphos como "codepoint ancho"
|
||||
auto Text::loadTextFile(const std::string& file_path) -> std::shared_ptr<File> {
|
||||
auto tf = std::make_shared<File>();
|
||||
|
||||
// No es necesario inicializar - los miembros tienen valores por defecto
|
||||
|
||||
// Load file using ResourceHelper (supports both filesystem and pack)
|
||||
auto file_data = Resource::Helper::loadFile(file_path);
|
||||
if (file_data.empty()) {
|
||||
std::cerr << "Error: Fichero no encontrado " << getFileName(file_path) << '\n';
|
||||
throw std::runtime_error("Fichero no encontrado: " + getFileName(file_path));
|
||||
}
|
||||
|
||||
// Convert bytes to string and parse
|
||||
std::string content(file_data.begin(), file_data.end());
|
||||
std::istringstream stream(content);
|
||||
std::string buffer;
|
||||
std::string line;
|
||||
int glyph_index = 0;
|
||||
|
||||
// Lee los dos primeros valores del fichero
|
||||
std::getline(stream, buffer);
|
||||
// Remove Windows line ending if present
|
||||
if (!buffer.empty() && buffer.back() == '\r') {
|
||||
buffer.pop_back();
|
||||
}
|
||||
std::getline(stream, buffer);
|
||||
// Remove Windows line ending if present
|
||||
if (!buffer.empty() && buffer.back() == '\r') {
|
||||
buffer.pop_back();
|
||||
}
|
||||
tf->box_width = std::stoi(buffer);
|
||||
while (std::getline(stream, line)) {
|
||||
if (!line.empty() && line.back() == '\r') { line.pop_back(); }
|
||||
if (line.empty() || line[0] == '#') { continue; }
|
||||
|
||||
std::getline(stream, buffer);
|
||||
// Remove Windows line ending if present
|
||||
if (!buffer.empty() && buffer.back() == '\r') {
|
||||
buffer.pop_back();
|
||||
}
|
||||
std::getline(stream, buffer);
|
||||
// Remove Windows line ending if present
|
||||
if (!buffer.empty() && buffer.back() == '\r') {
|
||||
buffer.pop_back();
|
||||
}
|
||||
tf->box_height = std::stoi(buffer);
|
||||
std::istringstream ls(line);
|
||||
std::string key;
|
||||
ls >> key;
|
||||
|
||||
// lee el resto de datos del fichero
|
||||
auto index = 32;
|
||||
auto line_read = 0;
|
||||
while (std::getline(stream, buffer)) {
|
||||
// Remove Windows line ending if present
|
||||
if (!buffer.empty() && buffer.back() == '\r') {
|
||||
buffer.pop_back();
|
||||
if (key == "box_width") {
|
||||
ls >> tf->box_width;
|
||||
} else if (key == "box_height") {
|
||||
ls >> tf->box_height;
|
||||
} else if (key == "columns") {
|
||||
ls >> tf->columns;
|
||||
} else if (key == "cell_spacing") {
|
||||
ls >> tf->cell_spacing;
|
||||
} else if (key == "row_spacing") {
|
||||
ls >> tf->row_spacing;
|
||||
} else {
|
||||
// Línea de glifo: codepoint_decimal ancho_visual
|
||||
uint32_t codepoint = 0;
|
||||
int width = 0;
|
||||
try {
|
||||
codepoint = static_cast<uint32_t>(std::stoul(key));
|
||||
ls >> width;
|
||||
} catch (...) {
|
||||
continue; // línea mal formateada, ignorar
|
||||
}
|
||||
Offset off{};
|
||||
const int row_sp = tf->row_spacing > 0 ? tf->row_spacing : tf->cell_spacing;
|
||||
off.x = (glyph_index % tf->columns) * (tf->box_width + tf->cell_spacing) + tf->cell_spacing;
|
||||
off.y = (glyph_index / tf->columns) * (tf->box_height + row_sp) + tf->cell_spacing;
|
||||
off.w = width;
|
||||
tf->offset[codepoint] = off;
|
||||
++glyph_index;
|
||||
}
|
||||
// Almacena solo las lineas impares
|
||||
if (line_read % 2 == 1) {
|
||||
tf->offset[index++].w = std::stoi(buffer);
|
||||
}
|
||||
|
||||
// Limpia el buffer
|
||||
buffer.clear();
|
||||
line_read++;
|
||||
};
|
||||
}
|
||||
|
||||
printWithDots("Text File : ", getFileName(file_path), "[ LOADED ]");
|
||||
|
||||
// Establece las coordenadas para cada caracter ascii de la cadena y su ancho
|
||||
for (int i = 32; i < 128; ++i) {
|
||||
tf->offset[i].x = ((i - 32) % 15) * tf->box_width;
|
||||
tf->offset[i].y = ((i - 32) / 15) * tf->box_height;
|
||||
}
|
||||
|
||||
return tf;
|
||||
}
|
||||
|
||||
// Constructor
|
||||
// Constructor desde fichero
|
||||
Text::Text(const std::shared_ptr<Surface>& surface, const std::string& text_file) {
|
||||
// Carga los offsets desde el fichero
|
||||
auto tf = loadTextFile(text_file);
|
||||
|
||||
// Inicializa variables desde la estructura
|
||||
box_height_ = tf->box_height;
|
||||
box_width_ = tf->box_width;
|
||||
offset_ = tf->offset;
|
||||
|
||||
// Crea los objetos
|
||||
sprite_ = std::make_unique<SurfaceSprite>(surface, (SDL_FRect){0.0F, 0.0F, static_cast<float>(box_width_), static_cast<float>(box_height_)});
|
||||
}
|
||||
|
||||
// Constructor
|
||||
// Constructor desde estructura precargada
|
||||
Text::Text(const std::shared_ptr<Surface>& surface, const std::shared_ptr<File>& text_file)
|
||||
: sprite_(std::make_unique<SurfaceSprite>(surface, (SDL_FRect){0.0F, 0.0F, static_cast<float>(text_file->box_width), static_cast<float>(text_file->box_height)})),
|
||||
box_width_(text_file->box_width),
|
||||
@@ -111,18 +136,22 @@ Text::Text(const std::shared_ptr<Surface>& surface, const std::shared_ptr<File>&
|
||||
// Escribe texto en pantalla
|
||||
void Text::write(int x, int y, const std::string& text, int kerning, int lenght) {
|
||||
int shift = 0;
|
||||
|
||||
if (lenght == -1) {
|
||||
lenght = text.length();
|
||||
}
|
||||
int glyphs_done = 0;
|
||||
size_t pos = 0;
|
||||
|
||||
sprite_->setY(y);
|
||||
for (int i = 0; i < lenght; ++i) {
|
||||
auto index = static_cast<int>(text[i]);
|
||||
sprite_->setClip(offset_[index].x, offset_[index].y, box_width_, box_height_);
|
||||
sprite_->setX(x + shift);
|
||||
sprite_->render(1, 15);
|
||||
shift += offset_[static_cast<int>(text[i])].w + kerning;
|
||||
while (pos < text.size()) {
|
||||
if (lenght != -1 && glyphs_done >= lenght) { break; }
|
||||
uint32_t cp = nextCodepoint(text, pos);
|
||||
auto it = offset_.find(cp);
|
||||
if (it == offset_.end()) { it = offset_.find('?'); }
|
||||
if (it != offset_.end()) {
|
||||
sprite_->setClip(it->second.x, it->second.y, box_width_, box_height_);
|
||||
sprite_->setX(x + shift);
|
||||
sprite_->render(1, 15);
|
||||
shift += it->second.w + kerning;
|
||||
}
|
||||
++glyphs_done;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,18 +186,22 @@ auto Text::writeDXToSurface(Uint8 flags, const std::string& text, int kerning, U
|
||||
// Escribe el texto con colores
|
||||
void Text::writeColored(int x, int y, const std::string& text, Uint8 color, int kerning, int lenght) {
|
||||
int shift = 0;
|
||||
|
||||
if (lenght == -1) {
|
||||
lenght = text.length();
|
||||
}
|
||||
int glyphs_done = 0;
|
||||
size_t pos = 0;
|
||||
|
||||
sprite_->setY(y);
|
||||
for (int i = 0; i < lenght; ++i) {
|
||||
auto index = static_cast<int>(text[i]);
|
||||
sprite_->setClip(offset_[index].x, offset_[index].y, box_width_, box_height_);
|
||||
sprite_->setX(x + shift);
|
||||
sprite_->render(1, color);
|
||||
shift += offset_[static_cast<int>(text[i])].w + kerning;
|
||||
while (pos < text.size()) {
|
||||
if (lenght != -1 && glyphs_done >= lenght) { break; }
|
||||
uint32_t cp = nextCodepoint(text, pos);
|
||||
auto it = offset_.find(cp);
|
||||
if (it == offset_.end()) { it = offset_.find('?'); }
|
||||
if (it != offset_.end()) {
|
||||
sprite_->setClip(it->second.x, it->second.y, box_width_, box_height_);
|
||||
sprite_->setX(x + shift);
|
||||
sprite_->render(1, color);
|
||||
shift += it->second.w + kerning;
|
||||
}
|
||||
++glyphs_done;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,8 +221,8 @@ void Text::writeCentered(int x, int y, const std::string& text, int kerning, int
|
||||
void Text::writeDX(Uint8 flags, int x, int y, const std::string& text, int kerning, Uint8 text_color, Uint8 shadow_distance, Uint8 shadow_color, int lenght) {
|
||||
const auto CENTERED = ((flags & CENTER_FLAG) == CENTER_FLAG);
|
||||
const auto SHADOWED = ((flags & SHADOW_FLAG) == SHADOW_FLAG);
|
||||
const auto COLORED = ((flags & COLOR_FLAG) == COLOR_FLAG);
|
||||
const auto STROKED = ((flags & STROKE_FLAG) == STROKE_FLAG);
|
||||
const auto COLORED = ((flags & COLOR_FLAG) == COLOR_FLAG);
|
||||
const auto STROKED = ((flags & STROKE_FLAG) == STROKE_FLAG);
|
||||
|
||||
if (CENTERED) {
|
||||
x -= (Text::length(text, kerning) / 2);
|
||||
@@ -213,22 +246,46 @@ void Text::writeDX(Uint8 flags, int x, int y, const std::string& text, int kerni
|
||||
writeColored(x, y, text, text_color, kerning, lenght);
|
||||
} else {
|
||||
writeColored(x, y, text, text_color, kerning, lenght);
|
||||
// write(x, y, text, kerning, lenght);
|
||||
}
|
||||
}
|
||||
|
||||
// Obtiene la longitud en pixels de una cadena
|
||||
// Obtiene la longitud en pixels de una cadena UTF-8
|
||||
auto Text::length(const std::string& text, int kerning) const -> int {
|
||||
int shift = 0;
|
||||
for (size_t i = 0; i < text.length(); ++i) {
|
||||
shift += (offset_[static_cast<int>(text[i])].w + kerning);
|
||||
size_t pos = 0;
|
||||
|
||||
while (pos < text.size()) {
|
||||
uint32_t cp = nextCodepoint(text, pos);
|
||||
auto it = offset_.find(cp);
|
||||
if (it == offset_.end()) { it = offset_.find('?'); }
|
||||
if (it != offset_.end()) {
|
||||
shift += it->second.w + kerning;
|
||||
}
|
||||
}
|
||||
|
||||
// Descuenta el kerning del último caracter
|
||||
return shift - kerning;
|
||||
return shift > 0 ? shift - kerning : 0;
|
||||
}
|
||||
|
||||
// Devuelve el valor de la variable
|
||||
// Devuelve el ancho en pixels de un glifo dado su codepoint Unicode
|
||||
auto Text::glyphWidth(uint32_t codepoint, int kerning) const -> int {
|
||||
auto it = offset_.find(codepoint);
|
||||
if (it == offset_.end()) { it = offset_.find('?'); }
|
||||
if (it != offset_.end()) { return it->second.w + kerning; }
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Devuelve el clip rect (región en el bitmap) de un glifo dado su codepoint
|
||||
auto Text::getGlyphClip(uint32_t codepoint) const -> SDL_FRect {
|
||||
auto it = offset_.find(codepoint);
|
||||
if (it == offset_.end()) { it = offset_.find('?'); }
|
||||
if (it == offset_.end()) { return {.x = 0.0F, .y = 0.0F, .w = 0.0F, .h = 0.0F}; }
|
||||
return {.x = static_cast<float>(it->second.x),
|
||||
.y = static_cast<float>(it->second.y),
|
||||
.w = static_cast<float>(box_width_),
|
||||
.h = static_cast<float>(box_height_)};
|
||||
}
|
||||
|
||||
// Devuelve el tamaño de la caja de cada caracter
|
||||
auto Text::getCharacterSize() const -> int {
|
||||
return box_width_;
|
||||
}
|
||||
@@ -236,4 +293,4 @@ auto Text::getCharacterSize() const -> int {
|
||||
// Establece si se usa un tamaño fijo de letra
|
||||
void Text::setFixedWidth(bool value) {
|
||||
fixed_width_ = value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include <array> // Para std::array
|
||||
#include <memory> // Para shared_ptr, unique_ptr
|
||||
#include <string> // Para string
|
||||
#include <memory> // Para shared_ptr, unique_ptr
|
||||
#include <string> // Para string
|
||||
#include <unordered_map> // Para unordered_map
|
||||
|
||||
#include "core/rendering/surface_sprite.hpp" // Para SSprite
|
||||
class Surface; // lines 8-8
|
||||
class Surface; // Forward declaration
|
||||
|
||||
// Clase texto. Pinta texto en pantalla a partir de un bitmap
|
||||
// Clase texto. Pinta texto en pantalla a partir de un bitmap con soporte UTF-8
|
||||
class Text {
|
||||
public:
|
||||
// Tipos anidados públicos
|
||||
@@ -18,9 +18,12 @@ class Text {
|
||||
};
|
||||
|
||||
struct File {
|
||||
int box_width{0}; // Anchura de la caja de cada caracter en el png
|
||||
int box_height{0}; // Altura de la caja de cada caracter en el png
|
||||
std::array<Offset, 128> offset{}; // Vector con las posiciones y ancho de cada letra
|
||||
int box_width{0}; // Anchura de la caja de cada caracter en el png
|
||||
int box_height{0}; // Altura de la caja de cada caracter en el png
|
||||
int columns{16}; // Número de columnas en el bitmap
|
||||
int cell_spacing{0}; // Píxeles de separación entre columnas (y borde izquierdo/superior)
|
||||
int row_spacing{0}; // Píxeles de separación entre filas (si difiere de cell_spacing)
|
||||
std::unordered_map<uint32_t, Offset> offset; // Posición y ancho de cada glifo (clave: codepoint Unicode)
|
||||
};
|
||||
|
||||
// Constructor
|
||||
@@ -45,20 +48,25 @@ class Text {
|
||||
auto writeToSurface(const std::string& text, int zoom = 1, int kerning = 1) -> std::shared_ptr<Surface>; // Escribe el texto en una textura
|
||||
auto writeDXToSurface(Uint8 flags, const std::string& text, int kerning = 1, Uint8 text_color = Uint8(), Uint8 shadow_distance = 1, Uint8 shadow_color = Uint8(), int lenght = -1) -> std::shared_ptr<Surface>; // Escribe el texto con extras en una textura
|
||||
|
||||
[[nodiscard]] auto length(const std::string& text, int kerning = 1) const -> int; // Obtiene la longitud en pixels de una cadena
|
||||
[[nodiscard]] auto getCharacterSize() const -> int; // Devuelve el tamaño del caracter
|
||||
[[nodiscard]] auto length(const std::string& text, int kerning = 1) const -> int; // Obtiene la longitud en pixels de una cadena
|
||||
[[nodiscard]] auto getCharacterSize() const -> int; // Devuelve el tamaño del caracter
|
||||
[[nodiscard]] auto glyphWidth(uint32_t codepoint, int kerning = 0) const -> int; // Devuelve el ancho en pixels de un glifo
|
||||
[[nodiscard]] auto getGlyphClip(uint32_t codepoint) const -> SDL_FRect; // Devuelve el clip rect del glifo
|
||||
[[nodiscard]] auto getSprite() const -> SurfaceSprite* { return sprite_.get(); } // Acceso al sprite interno
|
||||
|
||||
void setFixedWidth(bool value); // Establece si se usa un tamaño fijo de letra
|
||||
|
||||
static auto loadTextFile(const std::string& file_path) -> std::shared_ptr<File>; // Método de utilidad para cargar ficheros de texto
|
||||
static auto loadTextFile(const std::string& file_path) -> std::shared_ptr<File>; // Carga un fichero de definición de fuente .fnt
|
||||
static auto codepointToUtf8(uint32_t cp) -> std::string; // Convierte un codepoint Unicode a string UTF-8
|
||||
static auto nextCodepoint(const std::string& s, size_t& pos) -> uint32_t; // Extrae el siguiente codepoint UTF-8
|
||||
|
||||
private:
|
||||
// Objetos y punteros
|
||||
std::unique_ptr<SurfaceSprite> sprite_ = nullptr; // Objeto con los graficos para el texto
|
||||
|
||||
// Variables
|
||||
int box_width_ = 0; // Anchura de la caja de cada caracter en el png
|
||||
int box_height_ = 0; // Altura de la caja de cada caracter en el png
|
||||
bool fixed_width_ = false; // Indica si el texto se ha de escribir con longitud fija en todas las letras
|
||||
std::array<Offset, 128> offset_{}; // Vector con las posiciones y ancho de cada letra
|
||||
};
|
||||
int box_width_ = 0; // Anchura de la caja de cada caracter en el png
|
||||
int box_height_ = 0; // Altura de la caja de cada caracter en el png
|
||||
bool fixed_width_ = false; // Indica si el texto se ha de escribir con longitud fija
|
||||
std::unordered_map<uint32_t, Offset> offset_; // Posición y ancho de cada glifo (clave: codepoint Unicode)
|
||||
};
|
||||
|
||||
@@ -370,11 +370,11 @@ namespace Resource {
|
||||
std::cout << "\n>> CREATING TEXT_OBJECTS" << '\n';
|
||||
|
||||
std::vector<ResourceInfo> resources = {
|
||||
{.key = "aseprite", .texture_file = "aseprite.gif", .text_file = "aseprite.txt"},
|
||||
{.key = "gauntlet", .texture_file = "gauntlet.gif", .text_file = "gauntlet.txt"},
|
||||
{.key = "smb2", .texture_file = "smb2.gif", .text_file = "smb2.txt"},
|
||||
{.key = "subatomic", .texture_file = "subatomic.gif", .text_file = "subatomic.txt"},
|
||||
{.key = "8bithud", .texture_file = "8bithud.gif", .text_file = "8bithud.txt"}};
|
||||
{.key = "aseprite", .texture_file = "aseprite.gif", .text_file = "aseprite.fnt"},
|
||||
{.key = "gauntlet", .texture_file = "gauntlet.gif", .text_file = "gauntlet.fnt"},
|
||||
{.key = "smb2", .texture_file = "smb2.gif", .text_file = "smb2.fnt"},
|
||||
{.key = "subatomic", .texture_file = "subatomic.gif", .text_file = "subatomic.fnt"},
|
||||
{.key = "8bithud", .texture_file = "8bithud.gif", .text_file = "8bithud.fnt"}};
|
||||
|
||||
for (const auto& res_info : resources) {
|
||||
texts_.emplace_back(TextResource{.name = res_info.key, .text = std::make_shared<Text>(getSurface(res_info.texture_file), getTextFile(res_info.text_file))});
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
#include "core/audio/audio.hpp" // Para Audio
|
||||
#include "core/input/input.hpp" // Para Input, InputAction
|
||||
#include "core/locale/locale.hpp" // Para Locale
|
||||
#include "core/rendering/screen.hpp" // Para Screen
|
||||
#include "core/resources/resource_cache.hpp" // Para Resource
|
||||
#include "core/resources/resource_helper.hpp" // Para ResourceHelper
|
||||
@@ -162,6 +163,14 @@ Director::Director(std::vector<std::string> const& args) {
|
||||
|
||||
std::cout << "\n"; // Fin de inicialización de sistemas
|
||||
|
||||
// Inicializa el sistema de localización (antes de Cheevos que usa textos traducidos)
|
||||
#ifdef RELEASE_BUILD
|
||||
std::string locale_path = executable_path_ + PREFIX + "/data/locale/" + Options::language + ".yaml";
|
||||
Locale::init(locale_path);
|
||||
#else
|
||||
Locale::init(Resource::List::get()->get(Options::language + ".yaml"));
|
||||
#endif
|
||||
|
||||
// Special handling for cheevos.bin - also needs filesystem path
|
||||
#ifdef RELEASE_BUILD
|
||||
std::string cheevos_path = system_folder_ + "/cheevos.bin";
|
||||
@@ -177,6 +186,7 @@ Director::~Director() {
|
||||
|
||||
// Destruye los singletones
|
||||
Cheevos::destroy();
|
||||
Locale::destroy();
|
||||
#ifdef _DEBUG
|
||||
Debug::destroy();
|
||||
#endif
|
||||
|
||||
@@ -26,6 +26,7 @@ namespace Defaults::Video {
|
||||
constexpr Screen::Filter FILTER = Screen::Filter::NEAREST; // Filtro por defecto
|
||||
constexpr bool VERTICAL_SYNC = true; // Vsync activado por defecto
|
||||
constexpr bool POSTFX = false; // PostFX desactivado por defecto
|
||||
constexpr bool SUPERSAMPLING = false; // Supersampling desactivado por defecto
|
||||
constexpr bool INTEGER_SCALE = true; // Escalado entero activado por defecto
|
||||
constexpr bool KEEP_ASPECT = true; // Mantener aspecto activado por defecto
|
||||
constexpr const char* PALETTE_NAME = "zx-spectrum"; // Paleta por defecto
|
||||
@@ -81,6 +82,10 @@ namespace Defaults::Kiosk {
|
||||
constexpr bool INFINITE_LIVES = false; // Vidas infinitas en modo kiosko desactivadas por defecto
|
||||
} // namespace Defaults::Kiosk
|
||||
|
||||
namespace Defaults::Localization {
|
||||
constexpr const char* LANGUAGE = "ca"; // Idioma por defecto (en = inglés, ca = catalán)
|
||||
} // namespace Defaults::Localization
|
||||
|
||||
namespace Defaults::Game::Room {
|
||||
#ifdef _DEBUG
|
||||
constexpr const char* INITIAL = "51.yaml"; // Habitación de inicio en debug
|
||||
|
||||
@@ -8,8 +8,9 @@
|
||||
#include <iostream> // Para cout, cerr
|
||||
#include <utility>
|
||||
|
||||
#include "game/options.hpp" // Para Options, options
|
||||
#include "game/ui/notifier.hpp" // Para Notifier
|
||||
#include "core/locale/locale.hpp" // Para Locale
|
||||
#include "game/options.hpp" // Para Options, options
|
||||
#include "game/ui/notifier.hpp" // Para Notifier
|
||||
|
||||
// [SINGLETON]
|
||||
Cheevos* Cheevos::cheevos = nullptr;
|
||||
@@ -44,18 +45,19 @@ Cheevos::~Cheevos() {
|
||||
// Inicializa los logros
|
||||
void Cheevos::init() {
|
||||
cheevos_list_.clear();
|
||||
cheevos_list_.emplace_back(Achievement{.id = 1, .caption = "SHINY THINGS", .description = "Get 25% of the items", .icon = 2});
|
||||
cheevos_list_.emplace_back(Achievement{.id = 2, .caption = "HALF THE WORK", .description = "Get 50% of the items", .icon = 2});
|
||||
cheevos_list_.emplace_back(Achievement{.id = 3, .caption = "GETTING THERE", .description = "Get 75% of the items", .icon = 2});
|
||||
cheevos_list_.emplace_back(Achievement{.id = 4, .caption = "THE COLLECTOR", .description = "Get 100% of the items", .icon = 2});
|
||||
cheevos_list_.emplace_back(Achievement{.id = 5, .caption = "WANDERING AROUND", .description = "Visit 20 rooms", .icon = 2});
|
||||
cheevos_list_.emplace_back(Achievement{.id = 6, .caption = "I GOT LOST", .description = "Visit 40 rooms", .icon = 2});
|
||||
cheevos_list_.emplace_back(Achievement{.id = 7, .caption = "I LIKE TO EXPLORE", .description = "Visit all rooms", .icon = 2});
|
||||
cheevos_list_.emplace_back(Achievement{.id = 8, .caption = "FINISH THE GAME", .description = "Complete the game", .icon = 2});
|
||||
cheevos_list_.emplace_back(Achievement{.id = 9, .caption = "I WAS SUCKED BY A HOLE", .description = "Complete the game without entering the jail", .icon = 2});
|
||||
cheevos_list_.emplace_back(Achievement{.id = 10, .caption = "MY LITTLE PROJECTS", .description = "Complete the game with all items", .icon = 2});
|
||||
cheevos_list_.emplace_back(Achievement{.id = 11, .caption = "I LIKE MY MULTICOLOURED FRIENDS", .description = "Complete the game without dying", .icon = 2});
|
||||
cheevos_list_.emplace_back(Achievement{.id = 12, .caption = "SHIT PROJECTS DONE FAST", .description = "Complete the game in under 30 minutes", .icon = 2});
|
||||
auto* loc = Locale::get();
|
||||
cheevos_list_.emplace_back(Achievement{.id = 1, .caption = loc->get("achievements.c1"), .description = loc->get("achievements.d1"), .icon = 2});
|
||||
cheevos_list_.emplace_back(Achievement{.id = 2, .caption = loc->get("achievements.c2"), .description = loc->get("achievements.d2"), .icon = 2});
|
||||
cheevos_list_.emplace_back(Achievement{.id = 3, .caption = loc->get("achievements.c3"), .description = loc->get("achievements.d3"), .icon = 2});
|
||||
cheevos_list_.emplace_back(Achievement{.id = 4, .caption = loc->get("achievements.c4"), .description = loc->get("achievements.d4"), .icon = 2});
|
||||
cheevos_list_.emplace_back(Achievement{.id = 5, .caption = loc->get("achievements.c5"), .description = loc->get("achievements.d5"), .icon = 2});
|
||||
cheevos_list_.emplace_back(Achievement{.id = 6, .caption = loc->get("achievements.c6"), .description = loc->get("achievements.d6"), .icon = 2});
|
||||
cheevos_list_.emplace_back(Achievement{.id = 7, .caption = loc->get("achievements.c7"), .description = loc->get("achievements.d7"), .icon = 2});
|
||||
cheevos_list_.emplace_back(Achievement{.id = 8, .caption = loc->get("achievements.c8"), .description = loc->get("achievements.d8"), .icon = 2});
|
||||
cheevos_list_.emplace_back(Achievement{.id = 9, .caption = loc->get("achievements.c9"), .description = loc->get("achievements.d9"), .icon = 2});
|
||||
cheevos_list_.emplace_back(Achievement{.id = 10, .caption = loc->get("achievements.c10"), .description = loc->get("achievements.d10"), .icon = 2});
|
||||
cheevos_list_.emplace_back(Achievement{.id = 11, .caption = loc->get("achievements.c11"), .description = loc->get("achievements.d11"), .icon = 2});
|
||||
cheevos_list_.emplace_back(Achievement{.id = 12, .caption = loc->get("achievements.c12"), .description = loc->get("achievements.d12"), .icon = 2});
|
||||
}
|
||||
|
||||
// Busca un logro por id y devuelve el indice
|
||||
@@ -82,7 +84,7 @@ void Cheevos::unlock(int id) {
|
||||
cheevos_list_.at(INDEX).completed = true;
|
||||
|
||||
// Mostrar notificación en la pantalla
|
||||
Notifier::get()->show({"ACHIEVEMENT UNLOCKED!", cheevos_list_.at(INDEX).caption}, Notifier::Style::CHEEVO, -1, false);
|
||||
Notifier::get()->show({Locale::get()->get("achievements.header"), cheevos_list_.at(INDEX).caption}, Notifier::Style::CHEEVO, -1, false);
|
||||
|
||||
// Guardar el estado de los logros
|
||||
saveToFile();
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include "core/resources/resource_helper.hpp" // Para Resource::Helper
|
||||
#include "external/fkyaml_node.hpp" // Para fkyaml::node
|
||||
#include "game/options.hpp" // Para Options::language
|
||||
#include "utils/defines.hpp" // Para Tile::SIZE
|
||||
#include "utils/utils.hpp" // Para stringToColor
|
||||
|
||||
@@ -63,7 +64,10 @@ void RoomLoader::parseRoomConfig(const fkyaml::node& yaml, Room::Data& room, con
|
||||
room.number = file_name.substr(0, file_name.find_last_of('.'));
|
||||
|
||||
// Basic properties
|
||||
if (room_node.contains("name")) {
|
||||
const std::string LANG_KEY = "name_" + Options::language;
|
||||
if (room_node.contains(LANG_KEY)) {
|
||||
room.name = room_node[LANG_KEY].get_value<std::string>();
|
||||
} else if (room_node.contains("name")) {
|
||||
room.name = room_node["name"].get_value<std::string>();
|
||||
}
|
||||
if (room_node.contains("bgColor")) {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "core/locale/locale.hpp" // Para Locale
|
||||
#include "core/rendering/screen.hpp" // Para Screen
|
||||
#include "core/rendering/surface.hpp" // Para Surface
|
||||
#include "core/rendering/surface_animated_sprite.hpp" // Para SAnimatedSprite
|
||||
@@ -156,13 +157,13 @@ void Scoreboard::fillTexture() {
|
||||
auto text = Resource::Cache::get()->getText("smb2");
|
||||
const std::string TIME_TEXT = std::to_string((clock_.minutes % 100) / 10) + std::to_string(clock_.minutes % 10) + clock_.separator + std::to_string((clock_.seconds % 60) / 10) + std::to_string(clock_.seconds % 10);
|
||||
const std::string ITEMS_TEXT = std::to_string(data_->items / 100) + std::to_string((data_->items % 100) / 10) + std::to_string(data_->items % 10);
|
||||
text->writeColored(Tile::SIZE, LINE1, "Items collected ", data_->color);
|
||||
text->writeColored(Tile::SIZE, LINE1, Locale::get()->get("scoreboard.items"), data_->color);
|
||||
text->writeColored(17 * Tile::SIZE, LINE1, ITEMS_TEXT, items_color_);
|
||||
text->writeColored(20 * Tile::SIZE, LINE1, " Time ", data_->color);
|
||||
text->writeColored(20 * Tile::SIZE, LINE1, Locale::get()->get("scoreboard.time"), data_->color);
|
||||
text->writeColored(26 * Tile::SIZE, LINE1, TIME_TEXT, stringToColor("white"));
|
||||
|
||||
const std::string ROOMS_TEXT = std::to_string(data_->rooms / 100) + std::to_string((data_->rooms % 100) / 10) + std::to_string(data_->rooms % 10);
|
||||
text->writeColored(22 * Tile::SIZE, LINE2, "Rooms", stringToColor("white"));
|
||||
text->writeColored(22 * Tile::SIZE, LINE2, Locale::get()->get("scoreboard.rooms"), stringToColor("white"));
|
||||
text->writeColored(28 * Tile::SIZE, LINE2, ROOMS_TEXT, stringToColor("white"));
|
||||
|
||||
// Deja el renderizador como estaba
|
||||
|
||||
@@ -337,6 +337,22 @@ namespace Options {
|
||||
}
|
||||
}
|
||||
|
||||
if (vid.contains("supersampling")) {
|
||||
try {
|
||||
video.supersampling = vid["supersampling"].get_value<bool>();
|
||||
} catch (...) {
|
||||
video.supersampling = Defaults::Video::SUPERSAMPLING;
|
||||
}
|
||||
}
|
||||
|
||||
if (vid.contains("current_postfx_preset")) {
|
||||
try {
|
||||
current_postfx_preset = vid["current_postfx_preset"].get_value<int>();
|
||||
} catch (...) {
|
||||
current_postfx_preset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (vid.contains("vertical_sync")) {
|
||||
try {
|
||||
video.vertical_sync = vid["vertical_sync"].get_value<bool>();
|
||||
@@ -487,6 +503,21 @@ namespace Options {
|
||||
}
|
||||
}
|
||||
|
||||
// Carga configuración de idioma desde YAML
|
||||
void loadLocalizationFromYaml(const fkyaml::node& yaml) {
|
||||
if (yaml.contains("localization")) {
|
||||
const auto& loc = yaml["localization"];
|
||||
|
||||
if (loc.contains("language")) {
|
||||
try {
|
||||
language = loc["language"].get_value<std::string>();
|
||||
} catch (...) {
|
||||
language = Defaults::Localization::LANGUAGE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Crea e inicializa las opciones del programa
|
||||
void init() {
|
||||
#ifdef _DEBUG
|
||||
@@ -550,6 +581,7 @@ namespace Options {
|
||||
loadKeyboardControlsFromYaml(yaml);
|
||||
loadGamepadControlsFromYaml(yaml);
|
||||
loadKioskConfigFromYaml(yaml);
|
||||
loadLocalizationFromYaml(yaml);
|
||||
|
||||
if (console) {
|
||||
std::cout << "Config file loaded successfully\n\n";
|
||||
@@ -607,6 +639,8 @@ namespace Options {
|
||||
file << " fullscreen: " << (video.fullscreen ? "true" : "false") << "\n";
|
||||
file << " filter: " << filterToString(video.filter) << " # filter: nearest (pixel perfect) | linear (smooth)\n";
|
||||
file << " postfx: " << (video.postfx ? "true" : "false") << "\n";
|
||||
file << " supersampling: " << (video.supersampling ? "true" : "false") << "\n";
|
||||
file << " current_postfx_preset: " << current_postfx_preset << "\n";
|
||||
file << " vertical_sync: " << (video.vertical_sync ? "true" : "false") << "\n";
|
||||
file << " integer_scale: " << (video.integer_scale ? "true" : "false") << "\n";
|
||||
file << " keep_aspect: " << (video.keep_aspect ? "true" : "false") << "\n";
|
||||
@@ -640,6 +674,12 @@ namespace Options {
|
||||
file << " text: \"" << kiosk.text << "\"\n";
|
||||
file << " infinite_lives: " << (kiosk.infinite_lives ? "true" : "false") << "\n";
|
||||
|
||||
// LOCALIZATION
|
||||
file << "\n";
|
||||
file << "# LOCALIZATION (en = English, ca = Catalan)\n";
|
||||
file << "localization:\n";
|
||||
file << " language: \"" << language << "\"\n";
|
||||
|
||||
file.close();
|
||||
|
||||
if (console) {
|
||||
@@ -666,7 +706,6 @@ namespace Options {
|
||||
// Carga los presets de PostFX desde el fichero
|
||||
auto loadPostFXFromFile() -> bool {
|
||||
postfx_presets.clear();
|
||||
current_postfx_preset = 0;
|
||||
|
||||
std::ifstream file(postfx_file_path);
|
||||
if (!file.good()) {
|
||||
@@ -696,10 +735,21 @@ namespace Options {
|
||||
parseFloatField(p, "gamma", preset.gamma);
|
||||
parseFloatField(p, "curvature", preset.curvature);
|
||||
parseFloatField(p, "bleeding", preset.bleeding);
|
||||
parseFloatField(p, "flicker", preset.flicker);
|
||||
// Nota: 'supersampling' era un campo por-preset (eliminado). Si existe
|
||||
// en el fichero del usuario se ignora silenciosamente (compatible).
|
||||
postfx_presets.push_back(preset);
|
||||
}
|
||||
}
|
||||
|
||||
// Preservar el índice cargado desde config.yaml; clampar al rango válido.
|
||||
if (!postfx_presets.empty()) {
|
||||
current_postfx_preset = std::clamp(
|
||||
current_postfx_preset, 0, static_cast<int>(postfx_presets.size()) - 1);
|
||||
} else {
|
||||
current_postfx_preset = 0;
|
||||
}
|
||||
|
||||
if (console) {
|
||||
std::cout << "PostFX file loaded: " << postfx_presets.size() << " preset(s)\n";
|
||||
}
|
||||
@@ -737,6 +787,8 @@ namespace Options {
|
||||
file << "# gamma: gamma correction input 2.4 / output 2.2\n";
|
||||
file << "# curvature: CRT barrel distortion\n";
|
||||
file << "# bleeding: NTSC horizontal colour bleeding\n";
|
||||
file << "# flicker: phosphor CRT flicker ~50 Hz (0.0 = off, 1.0 = max)\n";
|
||||
file << "# Note: supersampling is a global toggle in config.yaml, not per-preset.\n";
|
||||
file << "\n";
|
||||
file << "presets:\n";
|
||||
file << " - name: \"CRT\"\n";
|
||||
@@ -747,6 +799,7 @@ namespace Options {
|
||||
file << " gamma: 0.8\n";
|
||||
file << " curvature: 0.0\n";
|
||||
file << " bleeding: 0.0\n";
|
||||
file << " flicker: 0.0\n";
|
||||
file << " - name: \"NTSC\"\n";
|
||||
file << " vignette: 0.4\n";
|
||||
file << " scanlines: 0.5\n";
|
||||
@@ -755,6 +808,7 @@ namespace Options {
|
||||
file << " gamma: 0.5\n";
|
||||
file << " curvature: 0.0\n";
|
||||
file << " bleeding: 0.6\n";
|
||||
file << " flicker: 0.0\n";
|
||||
file << " - name: \"CURVED\"\n";
|
||||
file << " vignette: 0.5\n";
|
||||
file << " scanlines: 0.6\n";
|
||||
@@ -763,6 +817,7 @@ namespace Options {
|
||||
file << " gamma: 0.7\n";
|
||||
file << " curvature: 0.8\n";
|
||||
file << " bleeding: 0.0\n";
|
||||
file << " flicker: 0.0\n";
|
||||
file << " - name: \"SCANLINES\"\n";
|
||||
file << " vignette: 0.0\n";
|
||||
file << " scanlines: 0.8\n";
|
||||
@@ -771,6 +826,7 @@ namespace Options {
|
||||
file << " gamma: 0.0\n";
|
||||
file << " curvature: 0.0\n";
|
||||
file << " bleeding: 0.0\n";
|
||||
file << " flicker: 0.0\n";
|
||||
file << " - name: \"SUBTLE\"\n";
|
||||
file << " vignette: 0.3\n";
|
||||
file << " scanlines: 0.4\n";
|
||||
@@ -779,6 +835,16 @@ namespace Options {
|
||||
file << " gamma: 0.3\n";
|
||||
file << " curvature: 0.0\n";
|
||||
file << " bleeding: 0.0\n";
|
||||
file << " flicker: 0.0\n";
|
||||
file << " - name: \"CRT LIVE\"\n";
|
||||
file << " vignette: 0.5\n";
|
||||
file << " scanlines: 0.6\n";
|
||||
file << " chroma: 0.3\n";
|
||||
file << " mask: 0.3\n";
|
||||
file << " gamma: 0.4\n";
|
||||
file << " curvature: 0.3\n";
|
||||
file << " bleeding: 0.4\n";
|
||||
file << " flicker: 0.8\n";
|
||||
|
||||
file.close();
|
||||
|
||||
@@ -788,11 +854,12 @@ namespace Options {
|
||||
|
||||
// Cargar los presets recién creados
|
||||
postfx_presets.clear();
|
||||
postfx_presets.push_back({"CRT", 0.6F, 0.7F, 0.15F, 0.6F, 0.8F, 0.0F, 0.0F});
|
||||
postfx_presets.push_back({"NTSC", 0.4F, 0.5F, 0.2F, 0.4F, 0.5F, 0.0F, 0.6F});
|
||||
postfx_presets.push_back({"CURVED", 0.5F, 0.6F, 0.1F, 0.5F, 0.7F, 0.8F, 0.0F});
|
||||
postfx_presets.push_back({"SCANLINES", 0.0F, 0.8F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F});
|
||||
postfx_presets.push_back({"SUBTLE", 0.3F, 0.4F, 0.05F, 0.0F, 0.3F, 0.0F, 0.0F});
|
||||
postfx_presets.push_back({"CRT", 0.6F, 0.7F, 0.3F, 0.6F, 0.8F, 0.0F, 0.0F, 0.0F});
|
||||
postfx_presets.push_back({"NTSC", 0.4F, 0.5F, 0.2F, 0.4F, 0.5F, 0.0F, 0.6F, 0.0F});
|
||||
postfx_presets.push_back({"CURVED", 0.5F, 0.6F, 0.1F, 0.5F, 0.7F, 0.8F, 0.0F, 0.0F});
|
||||
postfx_presets.push_back({"SCANLINES",0.0F, 0.8F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F});
|
||||
postfx_presets.push_back({"SUBTLE", 0.3F, 0.4F, 0.05F, 0.0F, 0.3F, 0.0F, 0.0F, 0.0F});
|
||||
postfx_presets.push_back({"CRT LIVE", 0.5F, 0.6F, 0.3F, 0.3F, 0.4F, 0.3F, 0.4F, 0.8F});
|
||||
current_postfx_preset = 0;
|
||||
|
||||
return true;
|
||||
|
||||
@@ -81,6 +81,7 @@ namespace Options {
|
||||
Screen::Filter filter{Defaults::Video::FILTER}; // Filtro usado para el escalado de la imagen
|
||||
bool vertical_sync{Defaults::Video::VERTICAL_SYNC}; // Indica si se quiere usar vsync o no
|
||||
bool postfx{Defaults::Video::POSTFX}; // Indica si se van a usar efectos PostFX o no
|
||||
bool supersampling{Defaults::Video::SUPERSAMPLING}; // Indica si el supersampling 3× está activo
|
||||
bool integer_scale{Defaults::Video::INTEGER_SCALE}; // Indica si el escalado de la imagen ha de ser entero en el modo a pantalla completa
|
||||
bool keep_aspect{Defaults::Video::KEEP_ASPECT}; // Indica si se ha de mantener la relación de aspecto al poner el modo a pantalla completa
|
||||
Border border{}; // Borde de la pantalla
|
||||
@@ -116,14 +117,15 @@ namespace Options {
|
||||
|
||||
// Estructura para un preset de PostFX
|
||||
struct PostFXPreset {
|
||||
std::string name; // Nombre del preset
|
||||
float vignette{0.6F}; // Intensidad de la viñeta (0.0 = ninguna, 1.0 = máxima)
|
||||
float scanlines{0.7F}; // Intensidad de las scanlines (0.0 = desactivadas, 1.0 = máximas)
|
||||
float chroma{0.15F}; // Intensidad de la aberración cromática (0.0 = ninguna, 1.0 = máxima)
|
||||
float mask{0.0F}; // Intensidad de la máscara de fósforo RGB (0.0 = desactivada, 1.0 = máxima)
|
||||
float gamma{0.0F}; // Corrección gamma input 2.4 / output 2.2 (0.0 = off, 1.0 = plena)
|
||||
float curvature{0.0F}; // Distorsión barrel CRT (0.0 = plana, 1.0 = máxima curvatura)
|
||||
float bleeding{0.0F}; // Sangrado de color NTSC horizontal Y/C (0.0 = off, 1.0 = máximo)
|
||||
std::string name; // Nombre del preset
|
||||
float vignette{0.6F}; // Intensidad de la viñeta (0.0 = ninguna, 1.0 = máxima)
|
||||
float scanlines{0.7F}; // Intensidad de las scanlines (0.0 = desactivadas, 1.0 = máximas)
|
||||
float chroma{0.15F}; // Intensidad de la aberración cromática (0.0 = ninguna, 1.0 = máxima)
|
||||
float mask{0.0F}; // Intensidad de la máscara de fósforo RGB (0.0 = desactivada, 1.0 = máxima)
|
||||
float gamma{0.0F}; // Corrección gamma input 2.4 / output 2.2 (0.0 = off, 1.0 = plena)
|
||||
float curvature{0.0F}; // Distorsión barrel CRT (0.0 = plana, 1.0 = máxima curvatura)
|
||||
float bleeding{0.0F}; // Sangrado de color NTSC horizontal Y/C (0.0 = off, 1.0 = máximo)
|
||||
float flicker{0.0F}; // Parpadeo de fósforo CRT ~50 Hz (0.0 = off, 1.0 = máximo)
|
||||
};
|
||||
|
||||
// --- Variables globales ---
|
||||
@@ -139,6 +141,9 @@ namespace Options {
|
||||
inline GamepadControls gamepad_controls{}; // Botones del gamepad usados para jugar
|
||||
inline Kiosk kiosk{}; // Opciones del modo kiosko
|
||||
|
||||
// Idioma del juego (establecido al inicio, sin cambio en caliente)
|
||||
inline std::string language{Defaults::Localization::LANGUAGE};
|
||||
|
||||
// Ruta completa del fichero de configuración (establecida mediante setConfigFile)
|
||||
inline std::string config_file_path{};
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "core/audio/audio.hpp" // Para Audio
|
||||
#include "core/input/global_inputs.hpp" // Para check
|
||||
#include "core/input/input.hpp" // Para Input
|
||||
#include "core/locale/locale.hpp" // Para Locale
|
||||
#include "core/rendering/pixel_reveal.hpp" // Para PixelReveal
|
||||
#include "core/rendering/screen.hpp" // Para Screen
|
||||
#include "core/rendering/surface.hpp" // Para Surface
|
||||
@@ -52,35 +53,35 @@ void Credits::handleInput() {
|
||||
|
||||
// Inicializa los textos
|
||||
void Credits::iniTexts() {
|
||||
std::string keys = "CURSORS";
|
||||
auto* loc = Locale::get();
|
||||
|
||||
texts_.clear();
|
||||
texts_.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({"INSTRUCTIONS:", static_cast<Uint8>(PaletteColor::YELLOW)});
|
||||
texts_.push_back({loc->get("credits.instructions"), static_cast<Uint8>(PaletteColor::YELLOW)});
|
||||
texts_.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({"HELP JAILDOC TO GET BACK ALL", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({"HIS PROJECTS AND GO TO THE", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({"JAIL TO FINISH THEM", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({loc->get("credits.l0"), static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({loc->get("credits.l1"), static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({loc->get("credits.l2"), static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
|
||||
texts_.push_back({"KEYS:", static_cast<Uint8>(PaletteColor::YELLOW)});
|
||||
texts_.push_back({loc->get("credits.keys"), static_cast<Uint8>(PaletteColor::YELLOW)});
|
||||
texts_.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({keys + " TO MOVE AND JUMP", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({"F8 TOGGLE THE MUSIC", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({"F11 PAUSE THE GAME", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({"F1-F2 WINDOWS SIZE", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({"F3 TOGGLE FULLSCREEN", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({"F9 TOOGLE BORDER SCREEN", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({loc->get("credits.keys_move"), static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({loc->get("credits.f8"), static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({loc->get("credits.f11"), static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({loc->get("credits.f1f2"), static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({loc->get("credits.f3"), static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({loc->get("credits.f9"), static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
|
||||
texts_.push_back({"A GAME BY JAILDESIGNER", static_cast<Uint8>(PaletteColor::YELLOW)});
|
||||
texts_.push_back({"MADE ON SUMMER/FALL 2022", static_cast<Uint8>(PaletteColor::YELLOW)});
|
||||
texts_.push_back({loc->get("credits.author"), static_cast<Uint8>(PaletteColor::YELLOW)});
|
||||
texts_.push_back({loc->get("credits.date"), static_cast<Uint8>(PaletteColor::YELLOW)});
|
||||
texts_.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
|
||||
texts_.push_back({"I LOVE JAILGAMES! ", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({loc->get("credits.love"), static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
texts_.push_back({"", static_cast<Uint8>(PaletteColor::WHITE)});
|
||||
}
|
||||
|
||||
|
||||