dopairb 0.2.0 → 0.5.0

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.
data/lib/dopairb/demo.rb CHANGED
@@ -7,8 +7,9 @@ module Dopairb
7
7
 
8
8
  module_function
9
9
 
10
- def ev(kind, info, flags: [], gain: 120, combo: 3, streak: 0)
11
- E.new(kind: kind, tier: nil, info: info, flags: flags, gain: gain, combo: combo, streak: streak, score: 12_480)
10
+ def ev(kind, info, flags: [], gain: 120, combo: 3, streak: 0, mult: 1, level: 5)
11
+ E.new(kind: kind, tier: nil, info: info, flags: flags, gain: gain, combo: combo, streak: streak, score: 12_480,
12
+ mult: mult, level: level)
12
13
  end
13
14
 
14
15
  def cases
@@ -33,6 +34,12 @@ module Dopairb
33
34
  ["1 + 1", ev(:success, { type: :integer, value: 2 }, flags: [:comeback], combo: 1, streak: 5, gain: 600)],
34
35
  ["loop {}", ev(:interrupt, { charge: 60 })],
35
36
  ["2**128", ev(:success, { type: :integer, value: 2**128 }, flags: [:new_record, :record_jump], gain: 420)],
37
+ ["[3, 1, 2].sort", ev(:success, { type: :array, size: 3 }, flags: [:critical], gain: 960, mult: 8)],
38
+ ["12.fdiv(5)", ev(:success, { type: :float, value: 2.4 }, flags: [:fever], combo: 12, gain: 1100, mult: 2)],
39
+ ["21.0 * 2", ev(:success, { type: :float, value: 42.0 }, flags: [:fever, :combo_best], combo: 13, gain: 1200, mult: 2)],
40
+ ["rand(777)", ev(:success, { type: :integer, value: 777 }, flags: [:jackpot], gain: 6_400, mult: 16)],
41
+ ["'level' * 2", ev(:success, { type: :string, length: 10, head: "levellevel", art: :great_wave, art_new: true, gallery: [1, 5] },
42
+ flags: [:level_up], gain: 200, level: 6)],
36
43
  ]
37
44
  end
38
45
 
@@ -6,7 +6,7 @@ module Dopairb
6
6
  class Director
7
7
  FPS = 40.0
8
8
 
9
- attr_reader :config
9
+ attr_reader :config, :rng
10
10
 
11
11
  def initialize(config, rng: Random.new)
12
12
  @config = config
@@ -50,20 +50,35 @@ module Dopairb
50
50
  Scenes::Banner.new(ctx, event, text: text, palette: palette, mega: true, rainbow: rainbow, sub: sub)
51
51
  end
52
52
  end
53
- if event.flag?(:comeback)
53
+ full = lambda { self.ctx(rows: ctx.rows, cols: ctx.w + 1).tap { |c| c.depth = ctx.depth } }
54
+ if event.flag?(:jackpot)
55
+ Scenes::Jackpot.new(ctx, event)
56
+ elsif event.flag?(:level_up) || (event.flag?(:art_drop) && info[:art])
57
+ if @config.motion && @config.level >= 2 && info[:art] && Scenes::Masterpiece.fits?(ctx.rows, ctx.w + 1)
58
+ Scenes::Masterpiece.new(full.(), event)
59
+ elsif event.flag?(:level_up)
60
+ mega.("LEVEL UP!", Color::NEON, rainbow: true, sub: "LV #{event.level}")
61
+ else
62
+ Scenes::Banner.new(ctx, event, text: "ART DROP!", palette: Color::GOLD, sub: Gallery.find(info[:art])&.title)
63
+ end
64
+ elsif event.flag?(:comeback)
54
65
  mega.(event.streak >= 2 ? "COMEBACK!" : "FIXED!", Color::GOLD, rainbow: event.streak >= 2)
55
66
  elsif event.flag?(:eval_milestone)
56
67
  mega.("#{Fx.number_with_commas(event_evals(event))} EVALS", Color::NEON, rainbow: true)
57
68
  elsif event.flag?(:record_jump)
58
69
  mega.("NEW RECORD", Color::GOLD, rainbow: true, sub: number_text(info))
59
70
  elsif event.flag?(:combo_mega)
60
- mega.("COMBO #{event.combo}!", Color::FIRE, rainbow: event.combo >= 50)
71
+ mega.("COMBO #{event.combo}!", Color::FIRE, rainbow: event.combo >= 50, sub: event.flag?(:fever_start) ? "FEVER TIME! ALL POINTS x2" : nil)
72
+ elsif event.flag?(:combo_best)
73
+ Scenes::Banner.new(ctx, event, text: "BEST COMBO!", palette: Color::FIRE, sub: "ALL-TIME BEST #{event.combo}")
61
74
  elsif info[:type] == :definition
62
75
  Scenes::Unlock.new(ctx, event)
63
76
  elsif event.flag?(:combo_milestone) && event.combo >= 5
64
77
  Scenes::Banner.new(ctx, event, text: "COMBO #{event.combo}", palette: Color::FIRE)
65
78
  elsif event.flag?(:first_hit)
66
79
  Scenes::Banner.new(ctx, event, text: "FIRST HIT!", palette: Color::ICE)
80
+ elsif event.flag?(:critical) && !counter?(event)
81
+ Scenes::Critical.new(ctx, event)
67
82
  elsif event.flag?(:output_rain)
68
83
  Scenes::Rain.new(ctx, event)
69
84
  else
@@ -71,6 +86,11 @@ module Dopairb
71
86
  end
72
87
  end
73
88
 
89
+ def counter?(event)
90
+ v = event.info[:value]
91
+ %i[integer float].include?(event.info[:type]) && (v.abs >= 10_000 || event.flag?(:new_record))
92
+ end
93
+
74
94
  def value_scene(event, ctx)
75
95
  info = event.info
76
96
  case info[:type]
@@ -92,9 +112,18 @@ module Dopairb
92
112
  c.input = nil if input && input.size + 12 > c.rows
93
113
  scene = scene_for(event, c)
94
114
  play(scene)
115
+ encore(event, c) if Scenes::Jackpot === scene
95
116
  scene
96
117
  end
97
118
 
119
+ # A jackpot pays out a masterpiece too: too good to fold away.
120
+ def encore(event, c)
121
+ return unless event.info[:art] && @config.motion && @config.level >= 2
122
+ return if Term.input_pending? || !Scenes::Masterpiece.fits?(c.rows, c.w + 1)
123
+ full = ctx(rows: c.rows, cols: c.w + 1).tap { |x| x.depth = c.depth }
124
+ play(Scenes::Masterpiece.new(full, event))
125
+ end
126
+
98
127
  # Cute loading screen until ready.call is true (e.g. the intro sound exists).
99
128
  def loading(&ready)
100
129
  return if @config.off?
@@ -105,9 +134,9 @@ module Dopairb
105
134
  raise if SystemExit === e || (SignalException === e && !(Interrupt === e))
106
135
  end
107
136
 
108
- def intro
137
+ def intro(career = nil)
109
138
  return if @config.off? || !@config.intro
110
- play(Scenes::Intro.new(ctx), force_trail: true)
139
+ play(Scenes::Intro.new(ctx, career), force_trail: true)
111
140
  end
112
141
 
113
142
  def outro(stats)
@@ -132,6 +161,7 @@ module Dopairb
132
161
  rescue Exception => e # rubocop:disable Lint/RescueException
133
162
  raise if SystemExit === e || (SignalException === e && !(Interrupt === e))
134
163
  # Never let an effect break the REPL; Ctrl-C during an effect just skips it.
164
+ Dopairb.debug(e) unless Interrupt === e
135
165
  end
136
166
 
137
167
  private
data/lib/dopairb/fx.rb CHANGED
@@ -111,6 +111,29 @@ module Dopairb
111
111
  width * scale
112
112
  end
113
113
 
114
+ # The big font squeezed into three rows with half blocks (▀ ▄ █).
115
+ # Returns the width drawn, or nil when the terminal lacks the glyphs.
116
+ def half_text(canvas, text, x, y, color_fn)
117
+ up = Term.glyph("▀", nil)
118
+ down = Term.glyph("▄", nil)
119
+ full = Term.glyph("█", nil)
120
+ return nil unless up && down && full
121
+ bm = Font.bitmap(text)
122
+ width = bm[0].size
123
+ 3.times do |r|
124
+ top = bm[r * 2]
125
+ bot = bm[r * 2 + 1] || []
126
+ width.times do |cx|
127
+ a = top[cx]
128
+ b = bot[cx]
129
+ next unless a || b
130
+ ch = a && b ? full : (a ? up : down)
131
+ canvas.put(x + cx, y + r, ch, color_fn.(cx, r, cx.fdiv([width - 1, 1].max)))
132
+ end
133
+ end
134
+ width
135
+ end
136
+
114
137
  def text_fits?(text, w, scale = 1)
115
138
  Font.width(text, scale: scale) <= w
116
139
  end