termfront 0.1.5 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +40 -0
- data/exe/termfront +2 -0
- data/lib/termfront/async_writer.rb +45 -0
- data/lib/termfront/audio_manager.rb +10 -2
- data/lib/termfront/color.rb +19 -0
- data/lib/termfront/config.rb +2 -0
- data/lib/termfront/drop_item/weapon.rb +4 -1
- data/lib/termfront/game.rb +78 -50
- data/lib/termfront/network/client.rb +32 -31
- data/lib/termfront/network/wavesfight_client.rb +2 -1
- data/lib/termfront/renderer.rb +369 -239
- data/lib/termfront/sprite.rb +60 -24
- data/lib/termfront/terminal_output.rb +31 -16
- data/lib/termfront/title_screen.rb +192 -49
- data/lib/termfront/version.rb +1 -1
- data/lib/termfront.rb +2 -0
- metadata +3 -1
data/lib/termfront/sprite.rb
CHANGED
|
@@ -4,46 +4,82 @@ module Termfront
|
|
|
4
4
|
module Sprite
|
|
5
5
|
module_function
|
|
6
6
|
|
|
7
|
+
EXECUTOR_EYE = Color.rgb_to_256(180, 120, 255)
|
|
8
|
+
EXECUTOR_HEAD = Color.rgb_to_256(130, 80, 220)
|
|
9
|
+
EXECUTOR_NECK = Color.rgb_to_256(90, 50, 180)
|
|
10
|
+
EXECUTOR_BODY = Color.rgb_to_256(80, 40, 160)
|
|
11
|
+
|
|
12
|
+
CRAWLER_EYE = Color.rgb_to_256(255, 240, 100)
|
|
13
|
+
CRAWLER_BODY = Color.rgb_to_256(220, 140, 30)
|
|
14
|
+
CRAWLER_LEG = Color.rgb_to_256(160, 100, 20)
|
|
15
|
+
|
|
16
|
+
PLAYER_EYE = Color.rgb_to_256(140, 220, 255)
|
|
17
|
+
PLAYER_HEAD = Color.rgb_to_256(40, 130, 180)
|
|
18
|
+
PLAYER_NECK = Color.rgb_to_256(30, 100, 160)
|
|
19
|
+
PLAYER_BODY = Color.rgb_to_256(25, 80, 140)
|
|
20
|
+
|
|
21
|
+
PLAYER_ENEMY_EYE = Color.rgb_to_256(210, 170, 165)
|
|
22
|
+
PLAYER_ENEMY_HEAD = Color.rgb_to_256(110, 80, 90)
|
|
23
|
+
PLAYER_ENEMY_NECK = Color.rgb_to_256(100, 50, 70)
|
|
24
|
+
PLAYER_ENEMY_BODY = Color.rgb_to_256(95, 30, 50)
|
|
25
|
+
|
|
26
|
+
DUMMY_HEAD = Color.rgb_to_256(235, 80, 80)
|
|
27
|
+
DUMMY_TORSO = Color.rgb_to_256(210, 210, 210)
|
|
28
|
+
DUMMY_LOWER = Color.rgb_to_256(200, 200, 200)
|
|
29
|
+
DUMMY_LEG = Color.rgb_to_256(180, 180, 180)
|
|
30
|
+
|
|
7
31
|
def executor(nx, ny)
|
|
8
|
-
return
|
|
9
|
-
return
|
|
10
|
-
return
|
|
11
|
-
return
|
|
12
|
-
return
|
|
13
|
-
return
|
|
14
|
-
return
|
|
32
|
+
return EXECUTOR_EYE if ((nx - 0.43) / 0.045)**2 + ((ny - 0.11) / 0.045)**2 <= 1.0
|
|
33
|
+
return EXECUTOR_EYE if ((nx - 0.57) / 0.045)**2 + ((ny - 0.11) / 0.045)**2 <= 1.0
|
|
34
|
+
return EXECUTOR_HEAD if ((nx - 0.5) / 0.18)**2 + ((ny - 0.12) / 0.12)**2 <= 1.0
|
|
35
|
+
return EXECUTOR_NECK if ((nx - 0.5) / 0.38)**2 + ((ny - 0.30) / 0.08)**2 <= 1.0
|
|
36
|
+
return EXECUTOR_BODY if ((nx - 0.5) / 0.25)**2 + ((ny - 0.50) / 0.22)**2 <= 1.0
|
|
37
|
+
return EXECUTOR_BODY if ((nx - 0.38) / 0.10)**2 + ((ny - 0.85) / 0.15)**2 <= 1.0
|
|
38
|
+
return EXECUTOR_BODY if ((nx - 0.62) / 0.10)**2 + ((ny - 0.85) / 0.15)**2 <= 1.0
|
|
15
39
|
|
|
16
40
|
nil
|
|
17
41
|
end
|
|
18
42
|
|
|
19
43
|
def crawler(nx, ny)
|
|
20
|
-
return
|
|
21
|
-
return
|
|
22
|
-
return
|
|
23
|
-
return
|
|
24
|
-
return
|
|
44
|
+
return CRAWLER_EYE if ((nx - 0.36) / 0.063)**2 + ((ny - 0.28) / 0.063)**2 <= 1.0
|
|
45
|
+
return CRAWLER_EYE if ((nx - 0.64) / 0.063)**2 + ((ny - 0.28) / 0.063)**2 <= 1.0
|
|
46
|
+
return CRAWLER_BODY if ((nx - 0.5) / 0.40)**2 + ((ny - 0.40) / 0.40)**2 <= 1.0
|
|
47
|
+
return CRAWLER_LEG if ((nx - 0.35) / 0.12)**2 + ((ny - 0.90) / 0.10)**2 <= 1.0
|
|
48
|
+
return CRAWLER_LEG if ((nx - 0.65) / 0.12)**2 + ((ny - 0.90) / 0.10)**2 <= 1.0
|
|
25
49
|
|
|
26
50
|
nil
|
|
27
51
|
end
|
|
28
52
|
|
|
29
53
|
def player(nx, ny)
|
|
30
|
-
return
|
|
31
|
-
return
|
|
32
|
-
return
|
|
33
|
-
return
|
|
34
|
-
return
|
|
35
|
-
return
|
|
36
|
-
return
|
|
54
|
+
return PLAYER_EYE if ((nx - 0.43) / 0.045)**2 + ((ny - 0.11) / 0.045)**2 <= 1.0
|
|
55
|
+
return PLAYER_EYE if ((nx - 0.57) / 0.045)**2 + ((ny - 0.11) / 0.045)**2 <= 1.0
|
|
56
|
+
return PLAYER_HEAD if ((nx - 0.5) / 0.18)**2 + ((ny - 0.12) / 0.12)**2 <= 1.0
|
|
57
|
+
return PLAYER_NECK if ((nx - 0.5) / 0.38)**2 + ((ny - 0.30) / 0.08)**2 <= 1.0
|
|
58
|
+
return PLAYER_BODY if ((nx - 0.5) / 0.25)**2 + ((ny - 0.50) / 0.22)**2 <= 1.0
|
|
59
|
+
return PLAYER_BODY if ((nx - 0.38) / 0.10)**2 + ((ny - 0.85) / 0.15)**2 <= 1.0
|
|
60
|
+
return PLAYER_BODY if ((nx - 0.62) / 0.10)**2 + ((ny - 0.85) / 0.15)**2 <= 1.0
|
|
61
|
+
|
|
62
|
+
nil
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def player_enemy(nx, ny)
|
|
66
|
+
return PLAYER_ENEMY_EYE if ((nx - 0.43) / 0.045)**2 + ((ny - 0.11) / 0.045)**2 <= 1.0
|
|
67
|
+
return PLAYER_ENEMY_EYE if ((nx - 0.57) / 0.045)**2 + ((ny - 0.11) / 0.045)**2 <= 1.0
|
|
68
|
+
return PLAYER_ENEMY_HEAD if ((nx - 0.5) / 0.18)**2 + ((ny - 0.12) / 0.12)**2 <= 1.0
|
|
69
|
+
return PLAYER_ENEMY_NECK if ((nx - 0.5) / 0.38)**2 + ((ny - 0.30) / 0.08)**2 <= 1.0
|
|
70
|
+
return PLAYER_ENEMY_BODY if ((nx - 0.5) / 0.25)**2 + ((ny - 0.50) / 0.22)**2 <= 1.0
|
|
71
|
+
return PLAYER_ENEMY_BODY if ((nx - 0.38) / 0.10)**2 + ((ny - 0.85) / 0.15)**2 <= 1.0
|
|
72
|
+
return PLAYER_ENEMY_BODY if ((nx - 0.62) / 0.10)**2 + ((ny - 0.85) / 0.15)**2 <= 1.0
|
|
37
73
|
|
|
38
74
|
nil
|
|
39
75
|
end
|
|
40
76
|
|
|
41
77
|
def training_dummy(nx, ny)
|
|
42
|
-
return
|
|
43
|
-
return
|
|
44
|
-
return
|
|
45
|
-
return
|
|
46
|
-
return
|
|
78
|
+
return DUMMY_HEAD if ((nx - 0.5) / 0.18)**2 + ((ny - 0.18) / 0.14)**2 <= 1.0
|
|
79
|
+
return DUMMY_TORSO if ((nx - 0.5) / 0.08)**2 + ((ny - 0.42) / 0.14)**2 <= 1.0
|
|
80
|
+
return DUMMY_LOWER if ((nx - 0.5) / 0.22)**2 + ((ny - 0.66) / 0.12)**2 <= 1.0
|
|
81
|
+
return DUMMY_LEG if ((nx - 0.38) / 0.08)**2 + ((ny - 0.90) / 0.12)**2 <= 1.0
|
|
82
|
+
return DUMMY_LEG if ((nx - 0.62) / 0.08)**2 + ((ny - 0.90) / 0.12)**2 <= 1.0
|
|
47
83
|
|
|
48
84
|
nil
|
|
49
85
|
end
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
module Termfront
|
|
4
4
|
module TerminalOutput
|
|
5
5
|
module_function
|
|
6
|
-
ANSI_PATTERN = /\e\[[0-9;]*[A-Za-z]/.freeze
|
|
7
6
|
|
|
8
7
|
def begin_frame(home: false, clear: false)
|
|
9
8
|
buf = +""
|
|
@@ -17,25 +16,41 @@ module Termfront
|
|
|
17
16
|
end
|
|
18
17
|
|
|
19
18
|
def fit_ansi(text, width)
|
|
20
|
-
visible = 0
|
|
21
19
|
out = +""
|
|
22
|
-
|
|
20
|
+
visible = 0
|
|
21
|
+
any_ansi = false
|
|
22
|
+
i = 0
|
|
23
|
+
len = text.bytesize
|
|
24
|
+
segment_start = 0
|
|
23
25
|
|
|
24
|
-
while
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
next
|
|
29
|
-
end
|
|
26
|
+
while i < len
|
|
27
|
+
byte = text.getbyte(i)
|
|
28
|
+
if byte == 0x1B
|
|
29
|
+
out << text.byteslice(segment_start, i - segment_start) if i > segment_start
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
esc_start = i
|
|
32
|
+
i += 1
|
|
33
|
+
while i < len
|
|
34
|
+
b = text.getbyte(i)
|
|
35
|
+
i += 1
|
|
36
|
+
break if (b >= 65 && b <= 90) || (b >= 97 && b <= 122)
|
|
37
|
+
end
|
|
38
|
+
out << text.byteslice(esc_start, i - esc_start)
|
|
39
|
+
any_ansi = true
|
|
40
|
+
segment_start = i
|
|
41
|
+
else
|
|
42
|
+
if (byte & 0xC0) != 0x80
|
|
43
|
+
break if visible >= width
|
|
44
|
+
|
|
45
|
+
visible += 1
|
|
46
|
+
end
|
|
47
|
+
i += 1
|
|
48
|
+
end
|
|
35
49
|
end
|
|
36
50
|
|
|
37
|
-
out <<
|
|
38
|
-
out <<
|
|
51
|
+
out << text.byteslice(segment_start, i - segment_start) if i > segment_start
|
|
52
|
+
out << "\e[0m" if any_ansi
|
|
53
|
+
(width - visible).times { out << " " } if visible < width
|
|
39
54
|
out
|
|
40
55
|
end
|
|
41
56
|
|
|
@@ -47,7 +62,7 @@ module Termfront
|
|
|
47
62
|
begin
|
|
48
63
|
written = io.syswrite(data.byteslice(total, bytes - total))
|
|
49
64
|
total += written
|
|
50
|
-
rescue IO::WaitWritable
|
|
65
|
+
rescue IO::WaitWritable, Errno::EAGAIN
|
|
51
66
|
IO.select(nil, [io])
|
|
52
67
|
end
|
|
53
68
|
end
|
|
@@ -7,12 +7,35 @@ module Termfront
|
|
|
7
7
|
[13.0, 8.0], [10.0, 8.5], [5.0, 8.5], [2.5, 5.0]
|
|
8
8
|
].freeze
|
|
9
9
|
|
|
10
|
+
TITLE_TEXT = "T E R M F R O N T"
|
|
11
|
+
SUB_TEXT = "Terminal FPS"
|
|
12
|
+
MENU_ITEMS = ["[P] PvP", "[F] Wavesfight", "[C] Campaign", "[S] Training", "[Q] Quit"].freeze
|
|
13
|
+
|
|
14
|
+
TITLE_CEIL_C = Color.rgb_to_256(0, 0, 95)
|
|
15
|
+
TITLE_FLOOR_C = Color.rgb_to_256(28, 28, 28)
|
|
16
|
+
TITLE_EXECUTOR_FALLBACK = Color.rgb_to_256(100, 60, 200)
|
|
17
|
+
TITLE_CRAWLER_FALLBACK = Color.rgb_to_256(220, 140, 30)
|
|
18
|
+
|
|
10
19
|
def initialize(stdout)
|
|
11
20
|
@stdout = stdout
|
|
12
21
|
@title_spin = 0.0
|
|
13
22
|
@demo_wp_idx = 0
|
|
14
23
|
@demo_wp_t = 0.0
|
|
15
24
|
@demo_fire = 0
|
|
25
|
+
|
|
26
|
+
mission_class = Mission::Base.campaign.first
|
|
27
|
+
if mission_class
|
|
28
|
+
m = mission_class.new
|
|
29
|
+
@demo_map = m.map_data.map { |row| row.is_a?(Array) ? row : row.chars }.freeze
|
|
30
|
+
@demo_map_h = @demo_map.size
|
|
31
|
+
@demo_map_w = @demo_map[0].size
|
|
32
|
+
@demo_enemies = m.enemy_defs.freeze
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
@static_lines_cols = 0
|
|
36
|
+
@static_title_line = nil
|
|
37
|
+
@static_sub_line = nil
|
|
38
|
+
@static_menu_lines = nil
|
|
16
39
|
end
|
|
17
40
|
|
|
18
41
|
def show
|
|
@@ -24,11 +47,15 @@ module Termfront
|
|
|
24
47
|
TerminalOutput.write_all(@stdout, TerminalOutput.begin_frame(home: true, clear: true) + TerminalOutput.end_frame)
|
|
25
48
|
|
|
26
49
|
STDIN.raw do |stdin|
|
|
50
|
+
last_render = clock - Config::RENDER_DT
|
|
27
51
|
loop do
|
|
28
52
|
now = clock
|
|
29
53
|
@title_spin += 0.015
|
|
30
54
|
|
|
31
|
-
|
|
55
|
+
if now - last_render >= Config::RENDER_DT
|
|
56
|
+
render
|
|
57
|
+
last_render = now
|
|
58
|
+
end
|
|
32
59
|
|
|
33
60
|
while IO.select([stdin], nil, nil, 0)
|
|
34
61
|
begin
|
|
@@ -60,6 +87,20 @@ module Termfront
|
|
|
60
87
|
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
61
88
|
end
|
|
62
89
|
|
|
90
|
+
def ensure_static_lines(cols)
|
|
91
|
+
return if @static_lines_cols == cols
|
|
92
|
+
|
|
93
|
+
tc = [(cols - TITLE_TEXT.size) / 2 + 1, 1].max
|
|
94
|
+
sc = [(cols - SUB_TEXT.size) / 2 + 1, 1].max
|
|
95
|
+
@static_title_line = TerminalOutput.fit_ansi("#{" " * (tc - 1)}\e[1;38;2;120;140;255m#{TITLE_TEXT}\e[0m", cols)
|
|
96
|
+
@static_sub_line = TerminalOutput.fit_ansi("#{" " * (sc - 1)}\e[38;2;80;80;120m#{SUB_TEXT}\e[0m", cols)
|
|
97
|
+
@static_menu_lines = MENU_ITEMS.map do |item|
|
|
98
|
+
ic = [(cols - item.size) / 2 + 1, 1].max
|
|
99
|
+
TerminalOutput.fit_ansi("#{" " * (ic - 1)}\e[97m#{item}\e[0m", cols)
|
|
100
|
+
end
|
|
101
|
+
@static_lines_cols = cols
|
|
102
|
+
end
|
|
103
|
+
|
|
63
104
|
def render
|
|
64
105
|
rows, cols = @stdout.winsize
|
|
65
106
|
rows = [rows, 10].max
|
|
@@ -76,13 +117,11 @@ module Termfront
|
|
|
76
117
|
virt_h = th * 2
|
|
77
118
|
color = Array.new(tw * virt_h, nil)
|
|
78
119
|
|
|
79
|
-
|
|
80
|
-
return unless mission
|
|
120
|
+
return unless @demo_map
|
|
81
121
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
dm_w = demo_map[0].size
|
|
122
|
+
demo_map = @demo_map
|
|
123
|
+
dm_h = @demo_map_h
|
|
124
|
+
dm_w = @demo_map_w
|
|
86
125
|
|
|
87
126
|
@demo_wp_t += Config::DEMO_SPEED
|
|
88
127
|
if @demo_wp_t >= 1.0
|
|
@@ -109,8 +148,8 @@ module Termfront
|
|
|
109
148
|
dists = Array.new(tw, 100.0)
|
|
110
149
|
horizon = (virt_h / 2 + bob).to_i
|
|
111
150
|
|
|
112
|
-
ceil_c =
|
|
113
|
-
floor_c =
|
|
151
|
+
ceil_c = TITLE_CEIL_C
|
|
152
|
+
floor_c = TITLE_FLOOR_C
|
|
114
153
|
|
|
115
154
|
tw.times do |col|
|
|
116
155
|
ray_a = cam_a - half_fov + fov * col.to_f / tw
|
|
@@ -167,9 +206,9 @@ module Termfront
|
|
|
167
206
|
flash = @demo_fire / 4.0 * (1.0 - dist / 4.0)
|
|
168
207
|
rr = (grey + flash * 160).to_i.clamp(0, 255)
|
|
169
208
|
gg = (grey + flash * 60).to_i.clamp(0, 255)
|
|
170
|
-
wall_c =
|
|
209
|
+
wall_c = Color.rgb_to_256(rr, gg, grey)
|
|
171
210
|
else
|
|
172
|
-
wall_c =
|
|
211
|
+
wall_c = Color.rgb_to_256(grey, grey, grey)
|
|
173
212
|
end
|
|
174
213
|
|
|
175
214
|
virt_h.times do |vr|
|
|
@@ -184,7 +223,7 @@ module Termfront
|
|
|
184
223
|
end
|
|
185
224
|
|
|
186
225
|
# Demo enemies
|
|
187
|
-
demo_enemies =
|
|
226
|
+
demo_enemies = @demo_enemies
|
|
188
227
|
ddx = Math.cos(cam_a)
|
|
189
228
|
ddy = Math.sin(cam_a)
|
|
190
229
|
ppx = -ddy * Math.tan(fov / 2.0)
|
|
@@ -237,54 +276,158 @@ module Termfront
|
|
|
237
276
|
sc = Sprite.for(type, nx, ny)
|
|
238
277
|
next unless sc
|
|
239
278
|
else
|
|
240
|
-
sc = type == :executor ?
|
|
279
|
+
sc = type == :executor ? TITLE_EXECUTOR_FALLBACK : TITLE_CRAWLER_FALLBACK
|
|
241
280
|
end
|
|
242
281
|
color[vr * tw + c] = sc
|
|
243
282
|
end
|
|
244
283
|
end
|
|
245
284
|
end
|
|
246
285
|
|
|
247
|
-
# Half-block rendering
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
286
|
+
# Half-block rendering - build each line directly to skip fit_ansi
|
|
287
|
+
fg_256 = Renderer::FG_256
|
|
288
|
+
bg_256 = Renderer::BG_256
|
|
289
|
+
cap_w = tw < cols ? tw : cols
|
|
290
|
+
|
|
291
|
+
r = 0
|
|
292
|
+
while r < th
|
|
293
|
+
vp0_offset = (r * 2) * tw
|
|
294
|
+
vp1_offset = vp0_offset + tw
|
|
295
|
+
|
|
296
|
+
first_tc = color[vp0_offset]
|
|
297
|
+
first_bc = color[vp1_offset]
|
|
298
|
+
|
|
299
|
+
if first_tc && first_tc == first_bc
|
|
300
|
+
uniform = true
|
|
301
|
+
cu = 1
|
|
302
|
+
while cu < cap_w
|
|
303
|
+
if color[vp0_offset + cu] != first_tc || color[vp1_offset + cu] != first_bc
|
|
304
|
+
uniform = false
|
|
305
|
+
break
|
|
306
|
+
end
|
|
307
|
+
cu += 1
|
|
308
|
+
end
|
|
309
|
+
if uniform
|
|
310
|
+
lines[r] = +bg_256[first_tc] << "\e[K\e[0m"
|
|
311
|
+
r += 1
|
|
312
|
+
next
|
|
313
|
+
end
|
|
314
|
+
elsif first_tc.nil? && first_bc.nil?
|
|
315
|
+
all_nil = true
|
|
316
|
+
cu = 1
|
|
317
|
+
while cu < cap_w
|
|
318
|
+
if !color[vp0_offset + cu].nil? || !color[vp1_offset + cu].nil?
|
|
319
|
+
all_nil = false
|
|
320
|
+
break
|
|
321
|
+
end
|
|
322
|
+
cu += 1
|
|
323
|
+
end
|
|
324
|
+
if all_nil
|
|
325
|
+
lines[r] = " " * cols
|
|
326
|
+
r += 1
|
|
327
|
+
next
|
|
328
|
+
end
|
|
329
|
+
end
|
|
330
|
+
|
|
251
331
|
line = +""
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
332
|
+
pfg = nil
|
|
333
|
+
pbg = nil
|
|
334
|
+
visible = 0
|
|
335
|
+
|
|
336
|
+
c = 0
|
|
337
|
+
while c < tw && visible < cap_w
|
|
338
|
+
tc = color[vp0_offset + c]
|
|
339
|
+
bc = color[vp1_offset + c]
|
|
340
|
+
|
|
341
|
+
if tc == bc
|
|
342
|
+
run_end = c + 1
|
|
343
|
+
while run_end < tw &&
|
|
344
|
+
color[vp0_offset + run_end] == tc &&
|
|
345
|
+
color[vp1_offset + run_end] == bc
|
|
346
|
+
run_end += 1
|
|
347
|
+
end
|
|
348
|
+
n = run_end - c
|
|
349
|
+
n = cap_w - visible if visible + n > cap_w
|
|
350
|
+
|
|
351
|
+
if tc.nil?
|
|
352
|
+
if pfg || pbg
|
|
353
|
+
line << "\e[0m"
|
|
354
|
+
pfg = nil
|
|
355
|
+
pbg = nil
|
|
356
|
+
end
|
|
357
|
+
line << (n == 1 ? " " : " " * n)
|
|
358
|
+
else
|
|
359
|
+
if pfg != tc || pbg
|
|
360
|
+
line << fg_256[tc]
|
|
361
|
+
line << "\e[49m" if pbg
|
|
362
|
+
pfg = tc
|
|
363
|
+
pbg = nil
|
|
364
|
+
end
|
|
365
|
+
line << (n == 1 ? "\xE2\x96\x88" : "\xE2\x96\x88" * n)
|
|
366
|
+
end
|
|
367
|
+
visible += n
|
|
368
|
+
c += n
|
|
369
|
+
else
|
|
370
|
+
if tc && bc
|
|
371
|
+
if pfg != tc || pbg != bc
|
|
372
|
+
line << fg_256[tc]
|
|
373
|
+
line << bg_256[bc]
|
|
374
|
+
pfg = tc
|
|
375
|
+
pbg = bc
|
|
376
|
+
end
|
|
377
|
+
line << "\xE2\x96\x80"
|
|
378
|
+
elsif tc
|
|
379
|
+
if pfg != tc || pbg
|
|
380
|
+
line << fg_256[tc]
|
|
381
|
+
line << "\e[49m" if pbg
|
|
382
|
+
pfg = tc
|
|
383
|
+
pbg = nil
|
|
384
|
+
end
|
|
385
|
+
line << "\xE2\x96\x80"
|
|
386
|
+
elsif bc
|
|
387
|
+
if pfg != bc || pbg
|
|
388
|
+
line << fg_256[bc]
|
|
389
|
+
line << "\e[49m" if pbg
|
|
390
|
+
pfg = bc
|
|
391
|
+
pbg = nil
|
|
392
|
+
end
|
|
393
|
+
line << "\xE2\x96\x84"
|
|
394
|
+
else
|
|
395
|
+
if pfg || pbg
|
|
396
|
+
line << "\e[0m"
|
|
397
|
+
pfg = nil
|
|
398
|
+
pbg = nil
|
|
399
|
+
end
|
|
400
|
+
line << " "
|
|
401
|
+
end
|
|
402
|
+
visible += 1
|
|
403
|
+
c += 1
|
|
404
|
+
end
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
if visible < cols
|
|
408
|
+
if pfg || pbg
|
|
409
|
+
line << "\e[0m"
|
|
410
|
+
pfg = nil
|
|
411
|
+
pbg = nil
|
|
412
|
+
end
|
|
413
|
+
line << (" " * (cols - visible))
|
|
268
414
|
end
|
|
269
|
-
|
|
415
|
+
line << "\e[0m" if pfg || pbg
|
|
416
|
+
|
|
417
|
+
lines[r] = line
|
|
418
|
+
r += 1
|
|
270
419
|
end
|
|
271
420
|
|
|
272
|
-
# Title text
|
|
421
|
+
# Title text + menu items (memoized per cols)
|
|
422
|
+
ensure_static_lines(cols)
|
|
423
|
+
|
|
273
424
|
title_row = [[th + 1, rows - 4].min, 1].max
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
# Menu items
|
|
282
|
-
items = ["[P] PvP", "[F] Wavesfight", "[C] Campaign", "[S] Training", "[Q] Quit"]
|
|
283
|
-
items_count_for_menu = items.size
|
|
284
|
-
menu_row = [[title_row + 2, rows - items_count_for_menu].min, 1].max
|
|
285
|
-
items.each_with_index do |item, i|
|
|
286
|
-
ic = [(cols - item.size) / 2 + 1, 1].max
|
|
287
|
-
lines[menu_row + i - 1] = TerminalOutput.fit_ansi("#{" " * (ic - 1)}\e[97m#{item}\e[0m", cols)
|
|
425
|
+
lines[title_row - 1] = @static_title_line
|
|
426
|
+
lines[title_row] = @static_sub_line
|
|
427
|
+
|
|
428
|
+
menu_row = [[title_row + 2, rows - MENU_ITEMS.size].min, 1].max
|
|
429
|
+
@static_menu_lines.each_with_index do |menu_line, i|
|
|
430
|
+
lines[menu_row + i - 1] = menu_line
|
|
288
431
|
end
|
|
289
432
|
|
|
290
433
|
lines.each_with_index do |line, index|
|
data/lib/termfront/version.rb
CHANGED
data/lib/termfront.rb
CHANGED
|
@@ -4,6 +4,7 @@ require "io/console"
|
|
|
4
4
|
|
|
5
5
|
require_relative "termfront/version"
|
|
6
6
|
require_relative "termfront/config"
|
|
7
|
+
require_relative "termfront/color"
|
|
7
8
|
require_relative "termfront/map"
|
|
8
9
|
require_relative "termfront/weapon/base"
|
|
9
10
|
require_relative "termfront/weapon/pistol"
|
|
@@ -32,6 +33,7 @@ require_relative "termfront/remote_enemy"
|
|
|
32
33
|
require_relative "termfront/sprite"
|
|
33
34
|
require_relative "termfront/input"
|
|
34
35
|
require_relative "termfront/terminal_output"
|
|
36
|
+
require_relative "termfront/async_writer"
|
|
35
37
|
require_relative "termfront/renderer"
|
|
36
38
|
require_relative "termfront/demo_player"
|
|
37
39
|
require_relative "termfront/scene_player"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: termfront
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.7
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- S-H-GAMELINKS
|
|
@@ -51,7 +51,9 @@ files:
|
|
|
51
51
|
- exe/termfront
|
|
52
52
|
- exe/termfront-server
|
|
53
53
|
- lib/termfront.rb
|
|
54
|
+
- lib/termfront/async_writer.rb
|
|
54
55
|
- lib/termfront/audio_manager.rb
|
|
56
|
+
- lib/termfront/color.rb
|
|
55
57
|
- lib/termfront/config.rb
|
|
56
58
|
- lib/termfront/demo_player.rb
|
|
57
59
|
- lib/termfront/drop_item/base.rb
|