aromancer 0.0.6 → 0.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e0cceb1c6a55e9d5753254eb63ee964d5607a6d1cf2726bb84cce84992cdc5c8
4
- data.tar.gz: 8c9b7c1dc2d9d5366f1aa32aa0b40c60d77f31a8779f3a818da897f1e20fc73e
3
+ metadata.gz: 5ebbde2a81b320eab73f2035b03d5166c5bcec1c01eaef7e51e4a010a8ab8251
4
+ data.tar.gz: 044c185f6741090deb4e179c8716e35d23e1b6a775c42db683ee079db8cb1419
5
5
  SHA512:
6
- metadata.gz: 8d003f5fe55523266a5c68e7960e3e55eeaf8e2b687c5cd4d2bbeb1ea33e78d85d2c878e2309a5154c51eb84d053a1e593ddd9d7a92d9db5c031b223ef735257
7
- data.tar.gz: de814ec7a6c83262ff9d6b9b699bfb01943080ffe01a0436d570fc14a49991baea16138b9ba4741e7f654769cc2fe3a1efd2c8c71b13f11c84e0b74a1661919d
6
+ metadata.gz: d992314e5e012369313167b145991a687ec0cfaa2a4e6b8ef445f147333e64e287eb70e9208215fac91b6ef20b04e0b3f740ee20ffd7f3c1b60197ad536dd4ad
7
+ data.tar.gz: 9210fd3030350a65b7f56ee68be13296a2707514f9cb1cf378e792b95868ad08c0009ec7c6c7409d6060919ee28911b557b4b4e673b933f47790b50ea2a46b4f
data/README.md CHANGED
@@ -1 +1,27 @@
1
- ## aromancer gem
1
+ # [aromancer](https://rubygems.org/gems/aromancer)
2
+ ## word
3
+ ### sentence
4
+ #### scroll
5
+ #### chapter
6
+ ##### dictionary
7
+ ##### story
8
+ ###### legend
9
+ ###### [aromancer_serve](https://github.com/arowmancy/aromancer_serve)
10
+
11
+ `tl;dr`
12
+
13
+ ```bash
14
+ gem install aromancer && aromancer serve
15
+ ```
16
+ > then, from different terminal run
17
+ ```bash
18
+ aromancer
19
+ ```
20
+ #### `in-game`
21
+ > go to `configure` and verify settings
22
+
23
+ [rubygems](https://rubygems.org/gems/aromancer)
24
+ [license](http://opensource.org/licenses/MIT)
25
+ [issues](https://github.com/i2097i/aromancer/issues)
26
+
27
+ #### aromancer by i2097i is copyright (2026)
data/aromancer.gemspec CHANGED
@@ -13,7 +13,7 @@
13
13
  require_relative "lib/aromancer/version"
14
14
 
15
15
  Gem::Specification.new do |spec|
16
- spec.name = "aromancer"
16
+ spec.name = Aromancer.to_s.downcase
17
17
  spec.version = Aromancer::VERSION
18
18
  spec.authors = ["i2097i"]
19
19
  spec.email = ["i2097i@hotmail.com"]
@@ -24,7 +24,7 @@ Gem::Specification.new do |spec|
24
24
  spec.license = "MIT"
25
25
  spec.files = `git ls-files`.split("\n").reject{|p| p.match?(/^(spec|.release|.*.gem$)/)}
26
26
  spec.bindir = "bin"
27
- spec.executables = ["aromancer"]
27
+ spec.executables = [Aromancer.to_s.downcase]
28
28
  spec.require_paths = ["lib", "db"]
29
29
  spec.required_ruby_version = ">= 4.0.7"
30
30
 
data/bin/aromancer CHANGED
@@ -12,4 +12,8 @@
12
12
 
13
13
  require :aromancer.to_s
14
14
 
15
- Aromancer::Cli.run
15
+ if ARGV[0] == :serve.to_s
16
+ Aromancer::Serve.run
17
+ else
18
+ Aromancer::Cli.run
19
+ end
@@ -0,0 +1 @@
1
+ 2183e762fd2705e60f043abdb5db94f220945cad83e3dc6813bb0c03f5bd000cd3cf3b4628a470335b075ef8a6180644d9d6e18695f17bc202fe9d8cb3126068
data/lib/aromancer/api.rb CHANGED
@@ -13,19 +13,18 @@
13
13
  module Aromancer
14
14
  class Api
15
15
 
16
- DATE_FORMAT = "%A %d %b %Y %I:%M:%S %p"
17
-
18
16
  def self.storage_headers(result)
19
17
  result.kind_of?(Aromancer::Server::InternalError) ? nil : result.headers
20
18
  end
21
19
 
22
20
  def self.register_error(response)
23
- Aromancer::Storage.set_last_error({
21
+ le = {
24
22
  status: response.status,
25
23
  headers: storage_headers(response),
26
- body: response.body.to_s[0..444]
27
- })
28
-
24
+ body: response.body.to_s
25
+ }
26
+ Aromancer::Storage.set_last_error(le)
27
+ Aromancer.print_last_error
29
28
  signed_out = false
30
29
  signed_out = response.status == 401
31
30
  # error_body = nil
@@ -96,7 +95,7 @@ module Aromancer
96
95
  result = Aromancer::Server.sign_out
97
96
  # clear storage
98
97
  Aromancer::Storage.instance.clear_cache!
99
- Aromancer::Storage.set_signed_out_flag(true)
98
+ Aromancer::Storage.set_signed_out_flag(false)
100
99
  Aromancer::Storage.set_player(nil)
101
100
  Aromancer::Storage.set_legends(nil)
102
101
  Aromancer::Storage.set_arena(nil)
@@ -139,7 +138,18 @@ module Aromancer
139
138
  end
140
139
 
141
140
  def self.set_active_legend_id(active_legend_id)
141
+
142
+ previous_arena = Aromancer::Storage.get_arena
142
143
  Aromancer::Storage.set_arena(nil)
144
+
145
+ # update local storage first
146
+ player = Aromancer::Storage.get_player
147
+ unless player.nil?
148
+ previous_active_legend_id = player["active_legend_id"]
149
+ player["active_legend_id"] = active_legend_id
150
+ Aromancer::Storage.set_player(player)
151
+ end
152
+ Aromancer::Storage.instance.clear_cache!
143
153
  result = Aromancer::Server.update_player({player: {
144
154
  active_legend_id: active_legend_id,
145
155
  status: active_legend_id.nil? ? :lobby : :playing
@@ -149,6 +159,14 @@ module Aromancer
149
159
  response = JSON.parse(result.body)
150
160
  Aromancer::Storage.set_player(response)
151
161
  else
162
+ # revert local storage
163
+ player = Aromancer::Storage.get_player
164
+ unless player.nil?
165
+ player["active_legend_id"] = previous_active_legend_id
166
+ Aromancer::Storage.set_player(player)
167
+ end
168
+ Aromancer::Storage.set_arena(previous_arena)
169
+
152
170
  register_error(result)
153
171
  end
154
172
  end
@@ -164,8 +182,8 @@ module Aromancer
164
182
  end
165
183
  end
166
184
 
167
- def self.load_stream
168
- result = Aromancer::Server.get_stream
185
+ def self.load_stream(count = nil)
186
+ result = Aromancer::Server.get_stream(count)
169
187
 
170
188
  if result.status == 200
171
189
  response = JSON.parse(result.body)
@@ -186,24 +204,24 @@ module Aromancer
186
204
  end
187
205
  end
188
206
 
189
- def self.create_turn(arena_params)
190
- result = Aromancer::Server.create_turn({arena: arena_params})
191
- if result.status == 201
207
+ def self.submit_turn(request_uuid, option = {})
208
+ result = Aromancer::Server.submit_turn(request_uuid, option)
209
+ if result.status == 200
192
210
  response = JSON.parse(result.body)
211
+ Aromancer::Storage.set_arena(response)
193
212
  else
194
213
  register_error(result)
195
214
  end
196
215
  end
197
216
 
198
- def self.update_turn(arena_params)
199
- result = Aromancer::Server.update_turn({arena: arena_params})
217
+ def self.load_rules
218
+ result = Aromancer::Server.load_rules
200
219
  if result.status == 200
201
- response = JSON.parse(result.body)
220
+ return JSON.parse(result.body)
202
221
  else
203
222
  register_error(result)
204
223
  end
205
224
  end
206
-
207
225
  end
208
226
 
209
227
  end
@@ -28,8 +28,24 @@ module Aromancer
28
28
  Aromancer::Prompt.instance.prompt
29
29
  end
30
30
 
31
- def self.say(message)
32
- (message.kind_of?(String) ? message.split("\n").each{|l| p.say(l.to_s.center(TTY::Screen.width))} : message)
31
+ def self.print_divider(text = nil)
32
+ puts "\n" if TTY::Screen.width > 99.9
33
+ self.p.say((text || "").center(TTY::Screen.width / 2.2, "-").center(TTY::Screen.width))
34
+ puts "\n" if TTY::Screen.width > 99.9
35
+ end
36
+
37
+ def self.say(message, ljust: false, rjust: false)
38
+ center = !ljust && !rjust
39
+ if message.kind_of?(String)
40
+ # puts "\n" if TTY::Screen.width > 99.9
41
+ message.split("\n").each{|l|
42
+ self.p.say(l.to_s.ljust(TTY::Screen.width)) if ljust
43
+ self.p.say(l.to_s.center(TTY::Screen.width)) if center
44
+ self.p.say(l.to_s.rjust(TTY::Screen.width)) if rjust
45
+ }
46
+ else
47
+ self.p.say(message)
48
+ end
33
49
  end
34
50
  end
35
51
 
@@ -13,6 +13,8 @@
13
13
  module Aromancer
14
14
  class Routes
15
15
 
16
+ WIDTH_MULTIPLIER = TTY::Screen.width / 4.0
17
+
16
18
  def self.resume
17
19
  return main_menu if Aromancer::Storage.get_signed_out_flag
18
20
 
@@ -28,12 +30,7 @@ module Aromancer
28
30
  rescue ArgumentError => e
29
31
  authentication
30
32
  end
31
- return
32
33
  end
33
-
34
- legend_menu if !active_legend.nil? &&
35
- (Aromancer::Storage.get_player && Aromancer::Storage.get_player&.symbolize_keys[:active_legend_id])
36
- authentication
37
34
  end
38
35
 
39
36
  def self.cls
@@ -58,9 +55,8 @@ module Aromancer
58
55
 
59
56
  if arena.nil?
60
57
  Aromancer.print_last_error("routes.legend.arena_failed")
61
- Aromancer::Api.set_active_legend_id(nil)
62
58
  Aromancer::Prompt.p.ask(I18n.t("shared.key_press"))
63
- main_menu
59
+ Aromancer::Api.set_active_legend_id(nil)
64
60
  else
65
61
  arena
66
62
  end
@@ -182,6 +178,20 @@ module Aromancer
182
178
  Thread.main[:route] = __method__.to_sym
183
179
  end
184
180
 
181
+ def self.rules
182
+ return if Thread.main[:route] == __method__.to_sym
183
+ rules = Aromancer::Api.load_rules
184
+ Aromancer::Prompt.say(rules["rules"], ljust: true)
185
+
186
+ Thread.main[:menu_options][__method__.to_sym] = [
187
+ {name: I18n.t("shared.key_press"), value: :key_press}
188
+ ]
189
+ Thread.main[:menu_runners][__method__.to_sym] = [
190
+ {value: :key_press, proc: Proc.new{ main_menu }}
191
+ ]
192
+ Thread.main[:route] = __method__.to_sym
193
+ end
194
+
185
195
  def self.main_menu
186
196
  cls
187
197
  Aromancer::Prompt.say(I18n.t("shared.navigate", route: :main_menu)) if Aromancer::Storage.get_preference(:debug)
@@ -204,6 +214,7 @@ module Aromancer
204
214
  {name: I18n.t("routes.main_menu.new_game"), value: :new},
205
215
  {name: I18n.t("routes.main_menu.load_game"), value: :load},
206
216
  {name: I18n.t("routes.main_menu.find_game"), value: :find},
217
+ {name: I18n.t("routes.main_menu.rules"), value: :rules},
207
218
  {name: I18n.t("routes.main_menu.configure"), value: :configure},
208
219
  {name: I18n.t("routes.main_menu.sign_out"), value: :out},
209
220
  {name: I18n.t("shared.exit"), value: :exit}
@@ -227,6 +238,9 @@ module Aromancer
227
238
  {value: :configure, proc: Proc.new{
228
239
  configure
229
240
  }},
241
+ {value: :rules, proc: Proc.new{
242
+ rules
243
+ }},
230
244
  {value: :out, proc: Proc.new{
231
245
  case Aromancer::Prompt.p.select(I18n.t("shared.confirm"), [:no, :yes], cycle: true, per_page: 11)
232
246
  when :no
@@ -235,7 +249,10 @@ module Aromancer
235
249
  Aromancer::Api.sign_out
236
250
  authentication
237
251
  end
238
- }}
252
+ }},
253
+ {value: :exit, proc: Proc.new{
254
+ exit
255
+ }},
239
256
  ]
240
257
  Thread.main[:route] = __method__.to_sym
241
258
  end
@@ -301,7 +318,7 @@ module Aromancer
301
318
 
302
319
  Thread.main[:menu_options][__method__.to_sym] = [{name: I18n.t("shared.back"), value: :back}] + legend_array.map{|l|
303
320
  {
304
- name: "#{I18n.t("routes.legend.title")}_#{l["id"]} (#{l["status"]}) #{DateTime.parse(l["created_at"])&.strftime(Aromancer::Api::DATE_FORMAT)}",
321
+ name: "#{l["value_display"]} > #{l["status"]} > #{Aromancer.date_display(l["created_at"])}",
305
322
  value: l["id"]
306
323
  }
307
324
  }
@@ -331,19 +348,18 @@ module Aromancer
331
348
  Thread.main[:route] = __method__.to_sym
332
349
  end
333
350
 
334
- def self.stream
335
- Aromancer::Api.load_stream
351
+ def self.stream(display_only: false, recent_count: nil)
352
+ return if Thread.main[:route] == __method__.to_sym
353
+ Aromancer::Prompt.print_divider(I18n.t("routes.stream.title"))
354
+ Aromancer::Api.load_stream(recent_count)
336
355
  stream = Aromancer::Storage.get_stream
337
- Aromancer::Prompt.say(I18n.t("routes.stream.title"))
338
- Aromancer::Prompt.say([
339
- :timestamp,
340
- :description
341
- ].join(", "))
342
-
343
- stream["stream"].each{|e|
344
- Aromancer::Prompt.say("\n")
345
- Aromancer::Prompt.say([e["updated_at"], e["description"]].join("\n"))
356
+ stream["stream"].last(
357
+ recent_count.nil? ? stream["stream"].count : recent_count
358
+ ).each{|e|
359
+ Aromancer::Prompt.say("[#{Aromancer.time_display(e["updated_at"])}]: #{e["description"]}", ljust: true)
346
360
  }
361
+ Aromancer::Prompt.print_divider(I18n.t("routes.stream.end"))
362
+ return if display_only
347
363
 
348
364
  Thread.main[:menu_options][__method__.to_sym] ||= [{name: I18n.t("shared.key_press"), value: nil}]
349
365
  Thread.main[:menu_runners][__method__.to_sym] ||= [
@@ -360,34 +376,53 @@ module Aromancer
360
376
  al = active_legend
361
377
  if !al.nil?
362
378
  if al["status"] == "complete"
363
- Aromancer::Api.set_active_legend_id(nil)
364
- Aromancer::Prompt.say(I18n.t("routes.legend.legend_complete"))
365
- return legends
379
+ Thread.main[:menu_options][__method__.to_sym] = [
380
+ {name: I18n.t("shared.key_press"), value: :key_press}
381
+ ]
382
+ Thread.main[:menu_runners][__method__.to_sym] = [
383
+ {value: :key_press, proc: Proc.new{
384
+ Aromancer::Prompt.say(I18n.t("routes.legend.returning_to_main"))
385
+ Aromancer::Api.set_active_legend_id(nil)
386
+ legends
387
+ }}
388
+ ]
389
+ Thread.main[:route] = __method__.to_sym
390
+ return
366
391
  elsif al["status"] == "created"
367
392
  Thread.main[:menu_options][__method__.to_sym] = [
368
393
  {name: :reload, value: :reload}, {name: I18n.t("shared.back"), value: :back}
369
394
  ]
370
- Thread.main[:menu_runners][__method__.to_sym] ||= [
395
+ Thread.main[:menu_runners][__method__.to_sym] = [
371
396
  {value: :reload, proc: Proc.new{ legend_menu }},
372
397
  {value: :back, proc: Proc.new{
373
398
  Aromancer::Api.set_active_legend_id(nil)
374
- main_menu
399
+ legends
375
400
  }}
376
401
  ]
377
402
  Thread.main[:route] = __method__.to_sym
378
403
  return
404
+ elsif active_legend["player"] && (active_legend["player"]["words"] || []).count == 0
405
+ Aromancer::Api.load_arena
406
+ return
379
407
  end
408
+ else
409
+ Thread.main[:menu_runners] = {}
410
+ Thread.main[:menu_options] = {}
411
+ Thread.main[:route] = :main_menu
380
412
  end
381
- hs = Aromancer::Storage.get_preference(:hide_sentences)
382
- hs_value = "#{hs ? "" : "hide_"}signed_sentences".to_sym
413
+
414
+ hide_sentences_pref = Aromancer::Storage.get_preference(:hide_sentences)
415
+ hide_sentences_pref_value = "#{hide_sentences_pref ? "" : "hide_"}signed_sentences".to_sym
416
+ hide_stream_pref = Aromancer::Storage.get_preference(:hide_stream)
417
+ hide_stream_pref_value = "#{hide_stream_pref ? "" : "hide_"}title".to_sym
383
418
 
384
419
  Thread.main[:route] = __method__.to_sym
385
420
  Thread.main[:menu_options][__method__.to_sym] = [
386
421
  {name: I18n.t("routes.legend.unspoken_words"), value: :words},
387
422
  {name: I18n.t("routes.legend.spoken_words"), value: :spoken_words},
388
423
  {name: I18n.t("routes.legend.unsigned_sentences"), value: :unsigned_sentences},
389
- {name: I18n.t("routes.legend.#{hs_value}"), value: hs_value},
390
- {name: I18n.t("routes.stream.title"), value: :stream},
424
+ {name: I18n.t("routes.legend.#{hide_sentences_pref_value}"), value: hide_sentences_pref_value},
425
+ {name: I18n.t("routes.stream.#{hide_stream_pref_value}"), value: hide_stream_pref_value},
391
426
  {name: I18n.t("routes.main_menu.title"), value: :main_menu}
392
427
  ]
393
428
 
@@ -395,11 +430,14 @@ module Aromancer
395
430
  {value: :words, proc: Proc.new{ words }},
396
431
  {value: :spoken_words, proc: Proc.new{ spoken_words }},
397
432
  {value: :unsigned_sentences, proc: Proc.new{ unsigned_sentences }},
398
- {value: hs_value, proc: Proc.new{
433
+ {value: hide_sentences_pref_value, proc: Proc.new{
399
434
  Aromancer::Storage.toggle_preference(:hide_sentences)
400
435
  legend_menu
401
436
  }},
402
- {value: :stream, proc: Proc.new{ stream }},
437
+ {value: hide_stream_pref_value, proc: Proc.new{
438
+ Aromancer::Storage.toggle_preference(:hide_stream)
439
+ legend_menu
440
+ }},
403
441
  {value: :main_menu, proc: Proc.new{
404
442
  Aromancer::Api.set_active_legend_id(nil)
405
443
  main_menu
@@ -415,54 +453,69 @@ module Aromancer
415
453
  al_status = ((al || {})["status"] || "").to_sym
416
454
  if !al.nil? &&
417
455
  [:created, :complete].include?(al_status)
456
+
457
+ stream(display_only: true) # display entire stream
458
+ Aromancer::Prompt.print_divider(al["value_display"])
418
459
  Aromancer::Prompt.say(arena["title"])
419
- Aromancer::Prompt.say(I18n.t("routes.legend.title"))
420
- Aromancer::Prompt.say(I18n.t("routes.legend.subtitle", subtitle: al["status"]))
421
- Aromancer::Prompt.say(I18n.t("routes.legend.players"))
422
- Aromancer::Prompt.say(JSON.pretty_generate(arena["players"]))
423
- Aromancer::Prompt.p.ask(I18n.t("shared.key_press"))
460
+ Aromancer::Prompt.say(arena["players"].map{|p| "#{p["alias"]}(#{p["score"]})"}.join(" | "))
461
+
424
462
  if al_status == :complete
425
- Aromancer::Api.set_active_legend_id(nil)
426
- sleep(1)
427
- return main_menu
463
+ Thread.main[:menu_options][:legend_menu] = [
464
+ {name: I18n.t("shared.key_press"), value: :key_press}
465
+ ]
466
+ Thread.main[:menu_runners][:legend_menu] = [
467
+ {value: :key_press, proc: Proc.new{
468
+ Aromancer::Prompt.say(I18n.t("routes.legend.returning_to_main"))
469
+ Aromancer::Api.set_active_legend_id(nil)
470
+ legends
471
+ }}
472
+ ]
428
473
  else
429
474
  Aromancer::Api.get_legends
430
- legend_menu
475
+
476
+ Thread.main[:menu_options][:legend_menu] = [
477
+ {name: I18n.t("shared.back"), value: :back},
478
+ {name: I18n.t("shared.key_press"), value: :key_press}
479
+ ]
480
+ Thread.main[:menu_runners][:legend_menu] = [
481
+ {value: :back, proc: Proc.new{
482
+ Aromancer::Prompt.say(I18n.t("routes.legend.returning_to_main"))
483
+ Aromancer::Api.set_active_legend_id(nil)
484
+ legends
485
+ }},
486
+ {value: :key_press, proc: Proc.new{ legend_menu }}
487
+ ]
431
488
  end
489
+ return
432
490
  end
433
491
 
434
492
  return if arena.nil? || arena["turn_player"].nil?
435
493
 
436
- # todo: pre-calculate needed widths. this isn't really working
437
- word_width = 5.0
438
- wpr = (TTY::Screen.width / word_width).floor
439
-
440
- # puts "wpr: #{wpr}"
441
- # puts TTY::Screen.width
442
-
443
494
  turn_player = arena["turn_player"]
444
495
 
445
496
  # title
446
- Aromancer::Prompt.say("\n\n")
447
- data = [
448
- [arena["title"]],
449
- ["#{turn_player["alias"]}'s turn"],
450
- ["dealer is #{arena["dealer"]["alias"]}"]
451
- ]
452
- title_table = TTY::Table.new(data)
453
- Aromancer::Prompt.say(title_table.render(:ascii))
454
-
455
- # players
456
- data = [
457
- [I18n.t("routes.legend.players")] + arena["players"].map{|p| "#{p["alias"]} (#{p["score"]})"}
458
- ]
459
- players_table = TTY::Table.new(data)
460
- Aromancer::Prompt.say(players_table.render(:ascii))
497
+ Aromancer::Prompt.say("\n")
498
+ ([
499
+ "#{I18n.t("routes.legend.title")}: #{(active_legend || {})["value_display"]}",
500
+ "#{arena["title"]}: #{turn_player["alias"]}'s turn. dealer is #{arena["dealer"]["alias"]}"
501
+ ] + arena["players"].map{|p| "#{p["alias"].rjust(11)} (#{p["score"]})"}
502
+ ).each{|l| Aromancer::Prompt.say(l, rjust: true)}
503
+
504
+ if !arena["bot_player"].nil?
505
+ # todo: show/hide preference
506
+ render_alchemy_for(arena["bot_player"])
507
+ end
508
+ render_scroll(arena)
509
+ render_alchemy_for(arena["player"])
510
+ end
461
511
 
512
+ # todo: move this to helper class. not a route
513
+ def self.render_scroll(arena)
514
+ Aromancer::Prompt.print_divider(I18n.t("routes.legend.scroll"))
462
515
  # spoken words
463
516
  Aromancer::Prompt.say(I18n.t("routes.legend.spoken_words"))
464
-
465
- data = arena["scroll_words"].map{|sw| sw["value_display"]}.each_slice(wpr).to_a || []
517
+ Aromancer::Prompt.say("\n")
518
+ data = arena["scroll_words"].map{|sw| sw["value_display"]}.each_slice(Aromancer::Routes::WIDTH_MULTIPLIER).to_a || []
466
519
  while data.any? && data.last.length < data.first.length
467
520
  data.last << ""
468
521
  end
@@ -472,34 +525,52 @@ module Aromancer
472
525
  unless arena["sentences"].empty?
473
526
  # unsigned sentences
474
527
  Aromancer::Prompt.say(I18n.t("routes.legend.unsigned_sentences"))
475
- data = arena["sentences"].map{|sw| sw["value_display"]}.each_slice(wpr).to_a || []
528
+ Aromancer::Prompt.say("\n")
529
+ data = arena["sentences"].map{|sw| sw["value_display"]}.each_slice(Aromancer::Routes::WIDTH_MULTIPLIER).to_a || []
476
530
  while data.any? && data.last.length < data.first.length
477
531
  data.last << ""
478
532
  end
479
533
  unsigned_sentences_table = TTY::Table.new(data)
480
- Aromancer::Prompt.say(unsigned_sentences_table.render(:unicode))
534
+ Aromancer::Prompt.say(unsigned_sentences_table.render)
481
535
  end
536
+ end
482
537
 
538
+ # todo: move this to helper class. not a route
539
+ def self.render_alchemy_for(player)
483
540
  # unspoken words
541
+ if player["id"].to_i != Aromancer::Storage.get_player["id"].to_i
542
+ Aromancer::Prompt.print_divider(I18n.t("routes.legend.alchemy_for", name: player["alias"]))
543
+ else
544
+ Aromancer::Prompt.print_divider(I18n.t("routes.legend.your_alchemy"))
545
+ end
484
546
  Aromancer::Prompt.say(I18n.t("routes.legend.unspoken_words"))
485
- data = arena["player"]["words"].map{|w| w["value_display"]}.each_slice(wpr).to_a || []
547
+ Aromancer::Prompt.say("\n\n")
548
+ words = player["words"].map{|w| w["value_display"]}
549
+ data = words.each_slice(Aromancer::Routes::WIDTH_MULTIPLIER).to_a || []
486
550
  while data.any? && data.last.length < data.first.length
487
551
  data.last << ""
488
552
  end
489
553
  words_table = TTY::Table.new(data)
490
554
  Aromancer::Prompt.say(words_table.render(:ascii))
491
555
 
492
- unless arena["player"]["sentences"].empty?
556
+ unless player["sentences"].empty?
493
557
  # signed sentences
494
- Aromancer::Prompt.say("#{I18n.t("routes.legend.signed_sentences")} (#{arena["player"]["sentences"].length})")
558
+ Aromancer::Prompt.say("#{I18n.t("routes.legend.signed_sentences")} (#{player["sentences"].length})")
495
559
  unless Aromancer::Storage.get_preference(:hide_sentences)
496
- data = arena["player"]["sentences"].map{|s| s["value_display"]}.each_slice(wpr).to_a || []
560
+ data = player["sentences"].map{|s| s["value_display"]}.each_slice(Aromancer::Routes::WIDTH_MULTIPLIER).to_a || []
497
561
  while data.any? && data.last.length < data.first.length
498
562
  data.last << ""
499
563
  end
500
564
  sentences_table = TTY::Table.new(data)
501
- Aromancer::Prompt.say(sentences_table.render(:ascii))
565
+ Aromancer::Prompt.say(sentences_table.render)
502
566
  end
567
+ Aromancer::Prompt.say("\n\n")
568
+ end
569
+
570
+ unless player["id"].to_i != Aromancer::Storage.get_player["id"].to_i ||
571
+ Aromancer::Storage.get_preference(:hide_stream)
572
+
573
+ stream(display_only: true, recent_count: 5)
503
574
  end
504
575
  end
505
576
 
@@ -548,7 +619,7 @@ module Aromancer
548
619
  arena = arena_data
549
620
  Thread.main[:menu_options][__method__.to_sym] = [
550
621
  {name: I18n.t("shared.back"), value: :back}
551
- ] + arena["sentences"].map{|s| {name: "id: #{s["id"]}, value: #{s["value"]}", value: s["id"]}}
622
+ ] + arena["sentences"].map{|s| {name: s["value_display"], value: s["id"]}}
552
623
 
553
624
  Thread.main[:menu_runners][__method__.to_sym] = [
554
625
  {value: :back, proc: Proc.new{ legend_menu }}
@@ -566,7 +637,7 @@ module Aromancer
566
637
 
567
638
  Aromancer::Prompt.say(I18n.t("shared.navigate", route: :word)) if Aromancer::Storage.get_preference(:debug)
568
639
  possibilities = Aromancer::Api.load_word_possibilities(selected_word_id)
569
-
640
+ request_uuid = possibilities["uuid"]
570
641
  if Aromancer::Storage.get_preference(:debug)
571
642
  Aromancer::Prompt.say(JSON.pretty_generate(possibilities))
572
643
  end
@@ -603,21 +674,11 @@ module Aromancer
603
674
  end
604
675
  }},
605
676
  {value: :player_word, proc: Proc.new{
606
- wytyd = I18n.t("routes.legend.place_on_scroll", word: selected_word["value_display"])
607
- Aromancer::Prompt.say(wytyd)
608
- Aromancer::Api.create_turn({
609
- wytyd: wytyd,
610
- word_id: selected_word["id"]
611
- })
677
+ Aromancer::Api.submit_turn(request_uuid)
612
678
  legend_menu
613
679
  }},
614
680
  {value: nil, proc: Proc.new{|o|
615
- if o["http_verb"] == "post"
616
- Aromancer::Api.create_turn(JSON.parse(o["payload"]))
617
- else
618
- Aromancer::Api.update_turn(JSON.parse(o["payload"]))
619
- end
620
-
681
+ Aromancer::Api.submit_turn(request_uuid, {option_uuid: o[:uuid.to_s]})
621
682
  legend_menu
622
683
  }}
623
684
  ]
@@ -141,7 +141,7 @@ module Aromancer
141
141
  end
142
142
  end
143
143
 
144
- def self.get_stream
144
+ def self.get_stream(count = nil)
145
145
  legend_id = (Aromancer::Storage.get_player || {})["active_legend_id"]
146
146
  return InternalError.build(StandardError.new("no active legend")) if legend_id.nil?
147
147
 
@@ -149,7 +149,7 @@ module Aromancer
149
149
  Faraday.new(
150
150
  url: Aromancer::Storage.get_server_url,
151
151
  headers: HEADERS.merge(auth_header),
152
- ).get("/legends/#{legend_id}/stream")
152
+ ).get("/legends/#{legend_id}/stream?count=#{count || nil}")
153
153
  rescue StandardError => e
154
154
  InternalError.build(e)
155
155
  end
@@ -169,7 +169,7 @@ module Aromancer
169
169
  end
170
170
  end
171
171
 
172
- def self.create_turn(params)
172
+ def self.submit_turn(request_uuid, params = {})
173
173
  legend_id = (Aromancer::Storage.get_player || {})["active_legend_id"]
174
174
  return InternalError.build(StandardError.new("no active legend")) if legend_id.nil?
175
175
 
@@ -178,22 +178,18 @@ module Aromancer
178
178
  url: Aromancer::Storage.get_server_url,
179
179
  headers: HEADERS.merge(auth_header),
180
180
  params: params
181
- ).post("/legends/#{legend_id}/arena")
181
+ ).put("/legends/#{legend_id}/arena/#{request_uuid}")
182
182
  rescue StandardError => e
183
183
  InternalError.build(e)
184
184
  end
185
185
  end
186
186
 
187
- def self.update_turn(params)
188
- legend_id = (Aromancer::Storage.get_player || {})["active_legend_id"]
189
- return InternalError.build(StandardError.new("no active legend")) if legend_id.nil?
190
-
187
+ def self.load_rules
191
188
  begin
192
189
  Faraday.new(
193
190
  url: Aromancer::Storage.get_server_url,
194
191
  headers: HEADERS.merge(auth_header),
195
- params: params
196
- ).put("/legends/#{legend_id}/arena")
192
+ ).get("/")
197
193
  rescue StandardError => e
198
194
  InternalError.build(e)
199
195
  end
@@ -12,7 +12,7 @@ module Aromancer
12
12
  class Storage
13
13
  include Singleton
14
14
 
15
- DEFAULT_SERVER = "http://aromancer.com"
15
+ DEFAULT_SERVER = "http://127.0.0.1"
16
16
 
17
17
  attr_accessor :storage_open, :cache
18
18
 
@@ -48,7 +48,7 @@ module Aromancer
48
48
  return Time.now.to_i
49
49
  end
50
50
 
51
- def self.get_preference(preference, default: :default)
51
+ def self.get_preference(preference, default: nil)
52
52
  p_key = "preference_#{preference}"
53
53
  p = instance.get_key(p_key)
54
54
  if p.nil?
@@ -64,7 +64,8 @@ module Aromancer
64
64
  end
65
65
 
66
66
  def self.toggle_preference(key)
67
- set_preference(key, !get_preference(key))
67
+ v = get_preference(key)
68
+ set_preference(key, !v)
68
69
  end
69
70
 
70
71
  def self.toggle_force_ssl
@@ -130,7 +131,7 @@ module Aromancer
130
131
 
131
132
  def self.set_server_url(server_url)
132
133
  uri = URI.parse(server_url)
133
- if uri.kind_of?(URI::HTTP) or uri.kind_of?(URI::HTTPS)
134
+ if uri.kind_of?(URI::HTTP) || uri.kind_of?(URI::HTTPS)
134
135
  URI_KEYS.each{|k|
135
136
  uri.kind_of?(URI::HTTP) && get_preference(:force_ssl) ? toggle_force_ssl : nil
136
137
  Aromancer::Storage.instance.set_key("server_url_#{k}", uri.select(k).first)
@@ -11,5 +11,5 @@
11
11
  =end
12
12
 
13
13
  module Aromancer
14
- VERSION = "0.0.6"
14
+ VERSION = "0.0.7"
15
15
  end
data/lib/aromancer.rb CHANGED
@@ -14,19 +14,33 @@ require_relative :reiquire.to_s
14
14
  Reiquire::aromancer
15
15
 
16
16
  module Aromancer
17
- THROTTLE_MS = 0.2
17
+ THROTTLE_MS = 0.1
18
+ ERROR_EXPIRATION = 7.77.to_f
18
19
  FONT = TTY::Font.new(:standard)
20
+ DATE_FORMAT = "%A %d %b %Y %I:%M:%S %p"
21
+ TIME_FORMAT = "%I:%M:%S %p"
19
22
 
20
23
  UNICODE = {
21
24
  close: "\u2A2F",
22
25
  check: "\u2713"
23
26
  }
24
27
 
28
+ class Serve
29
+ def self.run
30
+ unless Dir.exist?("#{Aromancer.to_s.downcase}_serve")
31
+ system("git clone git@github.com:arowmancy/aromancer_serve.git")
32
+ end
33
+ FileUtils.chdir :aromancer_serve.to_s do
34
+ system("bin/setup")
35
+ end
36
+ end
37
+ end
38
+
25
39
  # instance runs on main thread
26
40
  class Cli
27
41
  include Singleton
28
42
 
29
- attr_accessor :ui_thread, :ws_thread, :busy, :last_render
43
+ attr_accessor :ui_thread, :ws_thread, :busy, :ws_busy, :last_render, :error_timeout
30
44
 
31
45
  # user entry point
32
46
  def self.run
@@ -34,13 +48,16 @@ module Aromancer
34
48
  Aromancer::Storage.get_preference(:debug, default: false)
35
49
  Aromancer::Storage.get_preference(:force_ssl, default: true)
36
50
  Aromancer::Storage.get_preference(:hide_sentences, default: true)
51
+ Aromancer::Storage.get_preference(:hide_stream, default: true)
37
52
 
38
53
  self.instance.last_render = 0
54
+ self.instance.error_timeout = Time.now.to_i
39
55
 
40
56
  # load player on-start
41
57
  Aromancer::Api.set_active_legend_id(nil) unless Aromancer::Storage.get_player.nil?
42
58
 
43
59
  Thread.main[:route] = :authentication
60
+ Thread.main[:menu_runners] = {}
44
61
  Thread.main[:menu_options] = {}
45
62
  Aromancer::Prompt.say(I18n.t("shared.welcome", version: Aromancer::VERSION))
46
63
  Aromancer::Prompt.say(I18n.t("shared.server_url", url: Aromancer::Storage::get_server_url))
@@ -52,13 +69,15 @@ module Aromancer
52
69
  rescue NoMethodError => e
53
70
  if Aromancer::Storage.get_preference(:debug)
54
71
  Aromancer::Prompt.say(I18n.t("shared.last_error"))
55
- Aromancer::Prompt.say(e.inspect)
72
+ Aromancer::Prompt.say(JSON.pretty_generate(e[:body.to_s]))
73
+ Aromancer::Prompt.say("sleeping 5 on main thread...")
56
74
  sleep(5)
57
75
  end
58
76
  self.instance.start_ui_thread
59
77
  self.instance.start_ws_thread
60
78
  sleep(1)
61
79
  rescue Interrupt => e
80
+ Aromancer::Prompt.say("interrupt on main thread...exiting immediately.")
62
81
  exit
63
82
  end
64
83
  end
@@ -69,12 +88,13 @@ module Aromancer
69
88
  end
70
89
 
71
90
  def start_ui_thread(force = false)
72
- return if (@busy || Time.now - @last_render < 2) && !force
91
+ return if (@busy || Time.now - @last_render < 2.0) && !force
73
92
 
74
93
  @busy = true
75
94
  self.ui_thread&.exit
76
95
  self.ui_thread&.kill
77
96
  Thread.main[:menu_runners] = {}
97
+ Thread.main[:menu_options] = {}
78
98
  Aromancer::Prompt.instance.reload!
79
99
  self.ui_thread = Thread.new do
80
100
  loop do
@@ -82,8 +102,8 @@ module Aromancer
82
102
  menu_runners = Thread.main[:menu_runners][Thread.main[:route]]
83
103
  unless menu_options.nil? || menu_runners.nil?
84
104
  Aromancer::Routes.resume
85
- sleep(THROTTLE_MS)
86
105
  Aromancer.print_hud
106
+ sleep(THROTTLE_MS)
87
107
  v = Aromancer::Prompt.p.select("", menu_options, show_help: :always, cycle: true, per_page: 11)
88
108
  runners = menu_runners.select{|r| r[:value] == v}
89
109
  runners = menu_runners.select{|r| r[:value].nil?} if runners.empty?
@@ -91,32 +111,35 @@ module Aromancer
91
111
  if runners.any?
92
112
  r = runners.first
93
113
  r[:proc].call(v)
94
- else
95
- exit
96
114
  end
115
+
97
116
  else
98
117
  Aromancer::Routes.resume
99
118
  end
100
119
  Aromancer::Cli.instance.busy = false
101
120
  Aromancer::Cli.instance.last_render = Time.now
102
- # sleep(THROTTLE_MS)
121
+ sleep(THROTTLE_MS)
103
122
  end
104
123
  end
105
124
  end
106
125
 
107
126
  def start_ws_thread
127
+ return if @ws_busy
128
+ @ws_busy = true
108
129
  self.ws_thread.kill unless self.ws_thread.nil?
109
130
  self.ws_thread = Thread.new do
110
131
  Aromancer::Websocket.instance.disconnect
111
132
  loop do
112
133
  player = Aromancer::Storage.get_player
113
134
  if player.nil?
135
+ @ws_busy = true
114
136
  Aromancer::Websocket.instance.disconnect
115
137
  elsif !player["api_key"].nil?
116
138
  # attempt websocket connection
139
+ @ws_busy = true
117
140
  Aromancer::Websocket.instance.connect
118
141
  end
119
-
142
+ @ws_busy = false
120
143
  sleep(4)
121
144
  end
122
145
  end
@@ -132,7 +155,16 @@ module Aromancer
132
155
  "#{`echo $HOME`.strip}/.aromancer"
133
156
  end
134
157
 
158
+ def self.date_display(raw)
159
+ DateTime.parse(raw)&.strftime(Aromancer::DATE_FORMAT).downcase.gsub(" ", "_")
160
+ end
161
+
162
+ def self.time_display(raw)
163
+ DateTime.parse(raw)&.strftime(Aromancer::TIME_FORMAT).downcase.gsub(" ", "_")
164
+ end
165
+
135
166
  def self.print_hud
167
+ print_last_error
136
168
  websocket_status = "#{Aromancer::Storage.instance.get_key(:websocket_scheme)}: #{Aromancer::Websocket.instance.socket.nil? ? UNICODE[:close] : UNICODE[:check] }"
137
169
  player_status = if Aromancer::Storage.get_player.nil?
138
170
  I18n.t("routes.main_menu.not_signed_in")
@@ -141,13 +173,20 @@ module Aromancer
141
173
  end
142
174
 
143
175
  Aromancer::Prompt.say(
144
- [nil, player_status, websocket_status, nil].join(" | ")
176
+ [nil, :v.to_s + Aromancer::VERSION, player_status, websocket_status, nil,].join(" | ")
145
177
  )
146
178
  end
147
179
 
148
180
  def self.print_last_error(i18n_key = nil)
181
+ if Time.now.to_f - Aromancer::Cli.instance.error_timeout.to_f >= Aromancer::ERROR_EXPIRATION
182
+ Aromancer::Cli.instance.error_timeout = Time.now.to_i
183
+ Aromancer::Storage.set_last_error(nil)
184
+ return
185
+ end
186
+
149
187
  last_error = Aromancer::Storage.get_last_error
150
188
  return if last_error.nil?
189
+
151
190
  last_error = last_error.symbolize_keys
152
191
  message = last_error[:body]
153
192
  begin
@@ -156,7 +195,13 @@ module Aromancer
156
195
  rescue JSON::ParserError => e
157
196
  message = last_error[:body]
158
197
  end
159
- Aromancer::Prompt.say(I18n.t(i18n_key || "shared.last_error", status: last_error[:status], error: message))
160
- Aromancer::Storage.set_last_error(nil)
198
+
199
+ if message.kind_of?(Hash)
200
+ message = JSON.pretty_generate(message)
201
+ elsif message.kind_of?(String)
202
+ message = message[0..777]
203
+ end
204
+
205
+ Aromancer::Prompt.say(I18n.t(i18n_key || "shared.last_error", status: last_error[:status], error: message), rjust: true)
161
206
  end
162
207
  end
data/locale/en.yml CHANGED
@@ -29,6 +29,7 @@ en:
29
29
  new_game: "new game"
30
30
  load_game: "load game"
31
31
  find_game: "find game"
32
+ rules: "rules"
32
33
  player_count: "enter player count (1-2): "
33
34
  sign_out: "sign out"
34
35
  not_signed_in: "signed out"
@@ -43,14 +44,15 @@ en:
43
44
  debug: "debug (%{stored})"
44
45
  debug_toggle: "debug preference toggled to %{value}"
45
46
  new_game:
46
- player_count: "number of players"
47
- story_count: "number of stories"
47
+ player_count: "players"
48
+ story_count: "stories"
48
49
  starting: "starting new game..."
49
50
  status: "status"
50
51
  cancelled: "cancelled. game not created."
51
52
  legend:
52
53
  title: "legend"
53
54
  subtitle: "%{subtitle}"
55
+ alchemy_for: "alchemy_for_%{name}:"
54
56
  arena_failed: "arena failed to load (%{status}). %{error}"
55
57
  scroll: "scroll"
56
58
  spoken_words: "scroll words"
@@ -66,6 +68,8 @@ en:
66
68
  place_on_scroll: "place %{word} on the scroll."
67
69
  options_for_word: "available options for the %{word} word."
68
70
  last_error: "last error"
71
+ returning_to_main: "returning to main menu..."
72
+ your_alchemy: "alchemy"
69
73
  legends:
70
74
  help: ""
71
75
  legend_menu:
@@ -74,5 +78,5 @@ en:
74
78
  help: ""
75
79
  stream:
76
80
  title: "stream"
77
-
78
-
81
+ end: "eos"
82
+ hide_title: "hide stream"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aromancer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - i2097i
@@ -246,6 +246,7 @@ files:
246
246
  - checksums/aromancer-0.0.4.gem.sha512
247
247
  - checksums/aromancer-0.0.5.gem.sha512
248
248
  - checksums/aromancer-0.0.6.gem.sha512
249
+ - checksums/aromancer-0.0.7.gem.sha512
249
250
  - gem_graph.png
250
251
  - lib/aromancer.rb
251
252
  - lib/aromancer/.DS_Store