termfront 0.1.4 → 0.1.6
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 +43 -0
- data/exe/termfront +2 -0
- data/lib/termfront/config.rb +3 -1
- data/lib/termfront/game.rb +76 -50
- data/lib/termfront/network/client.rb +1 -1
- data/lib/termfront/network/server.rb +32 -6
- data/lib/termfront/renderer.rb +404 -245
- data/lib/termfront/terminal_output.rb +31 -21
- data/lib/termfront/title_screen.rb +51 -23
- data/lib/termfront/version.rb +1 -1
- metadata +1 -1
|
@@ -3,44 +3,54 @@
|
|
|
3
3
|
module Termfront
|
|
4
4
|
module TerminalOutput
|
|
5
5
|
module_function
|
|
6
|
-
ANSI_PATTERN = /\e\[[0-9;]*[A-Za-z]/.freeze
|
|
7
|
-
|
|
8
|
-
def sync_updates?
|
|
9
|
-
ENV.fetch("TERMFRONT_SYNC_UPDATES", "1") == "1"
|
|
10
|
-
end
|
|
11
6
|
|
|
12
7
|
def begin_frame(home: false, clear: false)
|
|
13
8
|
buf = +""
|
|
14
|
-
buf << "\e[?2026h" if sync_updates?
|
|
15
9
|
buf << "\e[H" if home
|
|
16
10
|
buf << "\e[2J" if clear
|
|
17
11
|
buf
|
|
18
12
|
end
|
|
19
13
|
|
|
20
14
|
def end_frame
|
|
21
|
-
|
|
15
|
+
""
|
|
22
16
|
end
|
|
23
17
|
|
|
24
18
|
def fit_ansi(text, width)
|
|
25
|
-
visible = 0
|
|
26
19
|
out = +""
|
|
27
|
-
|
|
20
|
+
visible = 0
|
|
21
|
+
any_ansi = false
|
|
22
|
+
i = 0
|
|
23
|
+
len = text.bytesize
|
|
24
|
+
segment_start = 0
|
|
28
25
|
|
|
29
|
-
while
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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
|
+
|
|
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
|
|
35
44
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
45
|
+
visible += 1
|
|
46
|
+
end
|
|
47
|
+
i += 1
|
|
48
|
+
end
|
|
40
49
|
end
|
|
41
50
|
|
|
42
|
-
out <<
|
|
43
|
-
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
|
|
44
54
|
out
|
|
45
55
|
end
|
|
46
56
|
|
|
@@ -7,12 +7,30 @@ 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
|
+
|
|
10
14
|
def initialize(stdout)
|
|
11
15
|
@stdout = stdout
|
|
12
16
|
@title_spin = 0.0
|
|
13
17
|
@demo_wp_idx = 0
|
|
14
18
|
@demo_wp_t = 0.0
|
|
15
19
|
@demo_fire = 0
|
|
20
|
+
|
|
21
|
+
mission_class = Mission::Base.campaign.first
|
|
22
|
+
if mission_class
|
|
23
|
+
m = mission_class.new
|
|
24
|
+
@demo_map = m.map_data.map { |row| row.is_a?(Array) ? row : row.chars }.freeze
|
|
25
|
+
@demo_map_h = @demo_map.size
|
|
26
|
+
@demo_map_w = @demo_map[0].size
|
|
27
|
+
@demo_enemies = m.enemy_defs.freeze
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
@static_lines_cols = 0
|
|
31
|
+
@static_title_line = nil
|
|
32
|
+
@static_sub_line = nil
|
|
33
|
+
@static_menu_lines = nil
|
|
16
34
|
end
|
|
17
35
|
|
|
18
36
|
def show
|
|
@@ -24,11 +42,15 @@ module Termfront
|
|
|
24
42
|
TerminalOutput.write_all(@stdout, TerminalOutput.begin_frame(home: true, clear: true) + TerminalOutput.end_frame)
|
|
25
43
|
|
|
26
44
|
STDIN.raw do |stdin|
|
|
45
|
+
last_render = clock - Config::RENDER_DT
|
|
27
46
|
loop do
|
|
28
47
|
now = clock
|
|
29
48
|
@title_spin += 0.015
|
|
30
49
|
|
|
31
|
-
|
|
50
|
+
if now - last_render >= Config::RENDER_DT
|
|
51
|
+
render
|
|
52
|
+
last_render = now
|
|
53
|
+
end
|
|
32
54
|
|
|
33
55
|
while IO.select([stdin], nil, nil, 0)
|
|
34
56
|
begin
|
|
@@ -60,6 +82,20 @@ module Termfront
|
|
|
60
82
|
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
61
83
|
end
|
|
62
84
|
|
|
85
|
+
def ensure_static_lines(cols)
|
|
86
|
+
return if @static_lines_cols == cols
|
|
87
|
+
|
|
88
|
+
tc = [(cols - TITLE_TEXT.size) / 2 + 1, 1].max
|
|
89
|
+
sc = [(cols - SUB_TEXT.size) / 2 + 1, 1].max
|
|
90
|
+
@static_title_line = TerminalOutput.fit_ansi("#{" " * (tc - 1)}\e[1;38;2;120;140;255m#{TITLE_TEXT}\e[0m", cols)
|
|
91
|
+
@static_sub_line = TerminalOutput.fit_ansi("#{" " * (sc - 1)}\e[38;2;80;80;120m#{SUB_TEXT}\e[0m", cols)
|
|
92
|
+
@static_menu_lines = MENU_ITEMS.map do |item|
|
|
93
|
+
ic = [(cols - item.size) / 2 + 1, 1].max
|
|
94
|
+
TerminalOutput.fit_ansi("#{" " * (ic - 1)}\e[97m#{item}\e[0m", cols)
|
|
95
|
+
end
|
|
96
|
+
@static_lines_cols = cols
|
|
97
|
+
end
|
|
98
|
+
|
|
63
99
|
def render
|
|
64
100
|
rows, cols = @stdout.winsize
|
|
65
101
|
rows = [rows, 10].max
|
|
@@ -76,13 +112,11 @@ module Termfront
|
|
|
76
112
|
virt_h = th * 2
|
|
77
113
|
color = Array.new(tw * virt_h, nil)
|
|
78
114
|
|
|
79
|
-
|
|
80
|
-
return unless mission
|
|
115
|
+
return unless @demo_map
|
|
81
116
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
dm_w = demo_map[0].size
|
|
117
|
+
demo_map = @demo_map
|
|
118
|
+
dm_h = @demo_map_h
|
|
119
|
+
dm_w = @demo_map_w
|
|
86
120
|
|
|
87
121
|
@demo_wp_t += Config::DEMO_SPEED
|
|
88
122
|
if @demo_wp_t >= 1.0
|
|
@@ -184,7 +218,7 @@ module Termfront
|
|
|
184
218
|
end
|
|
185
219
|
|
|
186
220
|
# Demo enemies
|
|
187
|
-
demo_enemies =
|
|
221
|
+
demo_enemies = @demo_enemies
|
|
188
222
|
ddx = Math.cos(cam_a)
|
|
189
223
|
ddy = Math.sin(cam_a)
|
|
190
224
|
ppx = -ddy * Math.tan(fov / 2.0)
|
|
@@ -269,22 +303,16 @@ module Termfront
|
|
|
269
303
|
lines[r] = TerminalOutput.fit_ansi(line, cols)
|
|
270
304
|
end
|
|
271
305
|
|
|
272
|
-
# Title text
|
|
306
|
+
# Title text + menu items (memoized per cols)
|
|
307
|
+
ensure_static_lines(cols)
|
|
308
|
+
|
|
273
309
|
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)
|
|
310
|
+
lines[title_row - 1] = @static_title_line
|
|
311
|
+
lines[title_row] = @static_sub_line
|
|
312
|
+
|
|
313
|
+
menu_row = [[title_row + 2, rows - MENU_ITEMS.size].min, 1].max
|
|
314
|
+
@static_menu_lines.each_with_index do |menu_line, i|
|
|
315
|
+
lines[menu_row + i - 1] = menu_line
|
|
288
316
|
end
|
|
289
317
|
|
|
290
318
|
lines.each_with_index do |line, index|
|
data/lib/termfront/version.rb
CHANGED