Class: Sunniesnow::Charter

Inherits:
Object
  • Object
show all
Includes:
BeatSeries
Defined in:
lib/sscharter/cli.rb,
lib/sscharter/charter.rb,
lib/sscharter/version.rb,
lib/sscharter/charter/beat.rb,
lib/sscharter/charter/check.rb,
lib/sscharter/charter/event.rb,
lib/sscharter/charter/group.rb,
lib/sscharter/charter/metadata.rb,
lib/sscharter/charter/tip_point.rb,
lib/sscharter/charter/basic_events.rb,
lib/sscharter/charter/events_manip.rb,
lib/sscharter/charter/story_events.rb

Defined Under Namespace

Modules: BeatSeries, CLI, Metronomic Classes: BeatState, Bookmark, BpmChangeList, Event, GroupState, OffsetError, TimeDependent, TipPointStart, Transform

Constant Summary collapse

PROJECT_DIR =

The project directory.

File.expand_path(ENV['SSCHARTER_PROJECT_DIR'] ||= Dir.pwd).freeze
VERSION =
"0.10.1"
COLORS =

Aliases for some colors that can be used with #difficulty_color.

{
	easy: '#3eb9fd',
	normal: '#f19e56',
	hard: '#e75e74',
	master: '#8c68f3',
	special: '#f156ee'
}.freeze
DIRECTIONS =

Aliases for some directions that can be used with #flick.

{
	right: %i[r],
	up_right: %i[ur ru],
	up: %i[u],
	up_left: %i[ul lu],
	left: %i[l],
	down_left: %i[dl ld],
	down: %i[d],
	down_right: %i[dr rd]
}.each_with_object({
	right: 0.0,
	up_right: Math::PI / 4,
	up: Math::PI / 2,
	up_left: Math::PI * 3 / 4,
	left: Math::PI,
	down_left: -Math::PI * 3 / 4,
	down: -Math::PI / 2,
	down_right: -Math::PI / 4
}) do |(direction_name, aliases), directions|
	aliases.each { directions[_1] = directions[direction_name] }
end.freeze
IMAGE_LAYER_ABOVE =
%i[none background bg_pattern hud fx judgement_line bg_notes notes circles tip_points fx_front].freeze
IMAGE_LAYER_ABOVE_SET =
IMAGE_LAYER_ABOVE.to_set.freeze
COORDINATE_SYSTEMS =
%i[canvas chart].freeze
COORDINATE_SYSTEMS_SET =
COORDINATE_SYSTEMS.to_set.freeze

Class Attribute Summary collapse

Instance Attribute Summary collapse

Attributes included from BeatSeries

#bpm_changes, #current_beat

DSL Methods collapse

Methods included from BeatSeries

#beat, #beat!, #bpm

Class Method Summary collapse

Instance Method Summary collapse

Methods included from BeatSeries

#current_beat_state, #restore_beat_state, #time_at

Constructor Details

#initialize(name) ⇒ Charter

Create a new chart. Usually you should use open instead of this method.

Parameters:

  • name (String)

    the name of the chart.



43
44
45
46
47
48
49
# File 'lib/sscharter/charter.rb', line 43

def initialize name
	@name = name
	init_chart_info
	init_beat_state
	init_group_state
	init_bookmarks
end

Class Attribute Details

.chartsHash{String => Sunniesnow::Charter} (readonly)

A hash containing all the charts opened by open. The keys are the names of the charts, and the values are the Sunniesnow::Charter objects.

Returns:



12
13
14
# File 'lib/sscharter/charter.rb', line 12

def charts
  @charts
end

Instance Attribute Details

#eventsArray<Event> (readonly)

An array of events.

Returns:



377
378
379
# File 'lib/sscharter/charter/event.rb', line 377

def events
  @events
end

Class Method Details

.open(name, &block) ⇒ Charter

Create a new chart or open an existing chart for editing. The name is used to check whether the chart already exists. If a new chart needs to be created, it is added to charts.

The given block will be evaluated in the context of the chart (inside the block, self is the same as the return value, a Sunniesnow::Charter instance). This method is intended to be called at the top level of a Ruby script to open a context for writing a Sunniesnow chart using the DSL.

In the examples in the documentation of other methods, it is assumed that they are run inside a block passed to this method.

Examples:

Sunniesnow::Charter.open 'master' do
  # write the chart here
end

Parameters:

  • name (String)

    the name of the chart.

Returns:



34
35
36
37
38
# File 'lib/sscharter/charter.rb', line 34

def self.open name, &block
	result = @charts[name] ||= new name
	result.instance_eval &block if block
	result
end

Instance Method Details

#artist(artist) ⇒ String

Set the artist of the music for the chart. This will be reflected in the return value of #to_sunniesnow.

Parameters:

  • artist (String)

    the artist of the music.

Returns:

  • (String)

    the artist of the music, the same as the argument artist.

Raises:

  • (ArgumentError)

    if artist is not a String.

See Also:



46
47
48
49
# File 'lib/sscharter/charter/metadata.rb', line 46

def artist artist
	raise ArgumentError, 'artist must be a string' unless artist.is_a? String
	@artist = artist
end

#at(name, goto_beat: true, preserve_beat: false, update_mark: false, &block) ⇒ Array<Event>

Parameters:

  • name (Object)

    the name of the bookmark to jump to.

  • goto_beat (Boolean) (defaults to: true)
  • preserve_beat (Boolean) (defaults to: false)
  • update_mark (Boolean) (defaults to: false)

Returns:

Raises:

  • (ArgumentError)


114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/sscharter/charter/group.rb', line 114

def at name, goto_beat: true, preserve_beat: false, update_mark: false, &block
	raise ArgumentError, 'no block given' unless block
	raise ArgumentError, "unknown bookmark #{name}" unless bookmark = @bookmarks[name]
	group_backup = current_group_state
	beat_backup = current_beat_state unless preserve_beat
	restore_group_state bookmark.group_state
	restore_beat_state bookmark.beat_state if goto_beat
	result = group &block
	mark name if update_mark
	restore_group_state group_backup
	restore_beat_state beat_backup unless preserve_beat
	result
end

#bg_note(x, y, duration_beats = 0, text = nil) ⇒ Event

Creates a background note at the given coordinates with the given duration and text. The coordinates x and y must be numbers. The argument duration_beats is the duration of the background note in beats. It needs to be a non-negative Rational or Integer. If it is a Float, it will be converted to a Rational, and a warning will be issued. The argument text is the text to be displayed on the note (it is converted to a string via to_s if it is not a string).

Both the duration_beats and the text arguments are optional. When there are three arguments given in total, the method determines whether the third is duration_beats or text based on its type.

Technically, this adds an event of type :bg_note to the chart at the current time with properties containing the information provided by x, y, duration_beats, and text.

Examples:

offset 0.1; bpm 120
bg_note 0, 0, 1, 'Hello' # duration is 1, text is 'Hello'
bg_note 50, 0, 'world'   # duration is 0, text is 'world'
bg_note -50, 0, 2        # duration is 2, text is ''

Parameters:

  • x (Numeric)

    the x-coordinate of the note.

  • y (Numeric)

    the y-coordinate of the note.

  • duration_beats (Rational, Integer) (defaults to: 0)

    the duration of the background note in beats.

  • text (String) (defaults to: nil)

    the text to be displayed on the note.

Returns:

  • (Event)

    the event representing the background note.

Raises:

  • (ArgumentError)

    if x, y, or duration_beats is not a number, or if duration_beats is negative.



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
# File 'lib/sscharter/charter/basic_events.rb', line 184

def bg_note x, y, duration_beats = 0, text = nil
	if text.nil?
		if duration_beats.is_a? String
			text = duration_beats
			duration_beats = 0
		else
			text = ''
		end
	end
	if !x.is_a?(Numeric) || !y.is_a?(Numeric) || !duration_beats.is_a?(Numeric)
		raise ArgumentError, 'x, y, and duration_beats must be numbers'
	end
	if duration_beats < 0
		raise ArgumentError, 'duration must be non-negative'
	end
	if duration_beats.is_a? Float
		warn 'Rational is recommended over Float for duration_beats'
	end
	event :bg_note, duration_beats.to_r, x: x.to_f, y: y.to_f, text: text.to_s
end

#big_text(duration_beats = 0, text) ⇒ Event

Creates a big text. The argument duration_beats is the duration of the big text in beats. It needs to be a non-negative Rational or Integer. If it is a Float, it will be converted to a Rational, and a warning will be issued. The argument text is the text to be displayed.

Technically, this adds an event of type :big_text to the chart at the current time with properties containing the information provided by duration_beats and text.

Examples:

offset 0.1; bpm 120
big_text 1, 'Hello, world!' # duration is 1, text is 'Hello, world!'
b 1
big_text 'Goodbye!'         # duration is 0, text is 'Goodbye!'

Parameters:

  • duration_beats (Rational, Integer) (defaults to: 0)

    the duration of the big text in beats.

  • text (String)

    the text to be displayed.

Returns:

  • (Event)

    the event representing the big text.

Raises:

  • (ArgumentError)

    if duration_beats is not a number or is negative.



222
223
224
225
226
227
228
229
230
231
232
233
# File 'lib/sscharter/charter/basic_events.rb', line 222

def big_text duration_beats = 0, text
	unless duration_beats.is_a? Numeric
		raise ArgumentError, 'duration_beats must be a number'
	end
	if duration_beats < 0
		raise ArgumentError, 'duration must be non-negative'
	end
	if duration_beats.is_a? Float
		warn 'Rational is recommended over Float for duration_beats'
	end
	event :big_text, duration_beats.to_r, text: text.to_s
end

#charter(charter) ⇒ String

Set the name of the chart author for the chart. This will be reflected in the return value of #to_sunniesnow.

Parameters:

  • charter (String)

    the name of the charter.

Returns:

  • (String)

    the name of the chart author, the same as the argument charter.

Raises:

  • (ArgumentError)

    if charter is not a String.

See Also:



57
58
59
60
# File 'lib/sscharter/charter/metadata.rb', line 57

def charter charter
	raise ArgumentError, 'charter must be a string' unless charter.is_a? String
	@charter = charter
end

#check(notes_in_bound: true, bg_notes_in_bound: true) ⇒ void

This method returns an undefined value.

Check the chart for potential issues.

Parameters:

  • notes_in_bound (Boolean) (defaults to: true)

    whether to check if tap/hold/drag/flick notes are spatially in bound.

  • bg_notes_in_bound (Boolean) (defaults to: true)

    whether to check if bg notes are spatially in bound.



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/sscharter/charter/check.rb', line 9

def check(
	notes_in_bound: true,
	bg_notes_in_bound: true
)
	out_of_bound_events = [] if notes_in_bound || bg_notes_in_bound
	@events.each do |event|
		if %i[tap hold drag flick drag_flick].include?(event.type) && notes_in_bound || event.type == :bg_note && bg_notes_in_bound
			if event[:x] < -100-1e-10 || event[:x] > 100+1e-10 || event[:y] < -50-1e-10 || event[:y] > 50+1e-10
				out_of_bound_events.push event
			end
		end
	end
	if notes_in_bound || bg_notes_in_bound
		if out_of_bound_events.empty?
			puts "===== All notes are in bound ====="
		else
			puts "===== Out-of-bound notes ====="
			out_of_bound_events.each do |event|
				p event
				puts "at time #{event.time}"
				puts 'defined at:'
				puts event.backtrace
			end
		end
	end
	nil
end

#checkerboard(duration_beats = 0) ⇒ Event

Creates a checkerboard background pattern. The argument duration_beats is the duration of the background pattern in beats. It needs to be a non-negative Rational or Integer. If it is a Float, it will be converted to a Rational, and a warning will be issued.

Technically, this adds an event of type :checkerboard to the chart at the current time with properties containing the information provided by duration_beats.

Examples:

offset 0.1; bpm 120
checkerboard 1 # duration is 1
b 2
checkerboard 2 # duration is 2

Parameters:

  • duration_beats (Rational, Integer) (defaults to: 0)

    the duration of the background pattern in beats.

Returns:

  • (Event)

    the event representing the background pattern.

Raises:

  • (ArgumentError)

    if duration_beats is not a number or is negative.



260
261
262
263
264
265
266
267
268
269
270
271
272
273
# File 'lib/sscharter/charter/basic_events.rb', line 260

%i[grid hexagon checkerboard diamond_grid pentagon turntable hexagram].each do |method_name|
	define_method method_name do |duration_beats = 0|
		unless duration_beats.is_a? Numeric
			raise ArgumentError, 'duration_beats must be a number'
		end
		if duration_beats < 0
			raise ArgumentError, 'duration must be non-negative'
		end
		if duration_beats.is_a? Float
			warn 'Rational is recommended over Float for duration_beats'
		end
		event method_name, duration_beats.to_r
	end
end

#current_group_stateGroupState

Note:

Internal API.

Returns:



62
63
64
65
66
67
68
69
70
71
72
# File 'lib/sscharter/charter/group.rb', line 62

def current_group_state
	GroupState.new(
		@tip_point_mode_stack.dup,
		@current_tip_point_stack.dup,
		@current_tip_point_group_stack.dup,
		@current_duplicate,
		@tip_point_start_stack.dup,
		@tip_point_start_to_add_stack.dup,
		@groups.dup
	)
end

#diamond_grid(duration_beats = 0) ⇒ Event

Creates a diamond grid background pattern. The argument duration_beats is the duration of the background pattern in beats. It needs to be a non-negative Rational or Integer. If it is a Float, it will be converted to a Rational, and a warning will be issued.

Technically, this adds an event of type :diamond_grid to the chart at the current time with properties containing the information provided by duration_beats.

Examples:

offset 0.1; bpm 120
diamond_grid 1 # duration is 1
b 2
diamond_grid 2 # duration is 2

Parameters:

  • duration_beats (Rational, Integer) (defaults to: 0)

    the duration of the background pattern in beats.

Returns:

  • (Event)

    the event representing the background pattern.

Raises:

  • (ArgumentError)

    if duration_beats is not a number or is negative.



260
261
262
263
264
265
266
267
268
269
270
271
272
273
# File 'lib/sscharter/charter/basic_events.rb', line 260

%i[grid hexagon checkerboard diamond_grid pentagon turntable hexagram].each do |method_name|
	define_method method_name do |duration_beats = 0|
		unless duration_beats.is_a? Numeric
			raise ArgumentError, 'duration_beats must be a number'
		end
		if duration_beats < 0
			raise ArgumentError, 'duration must be non-negative'
		end
		if duration_beats.is_a? Float
			warn 'Rational is recommended over Float for duration_beats'
		end
		event method_name, duration_beats.to_r
	end
end

#difficulty(difficulty) ⇒ String

Set the difficulty level for the chart. This will be reflected in the return value of #to_sunniesnow.

The argument difficulty should be a string representing the difficulty level. Anything other than a string will be converted to a string using to_s.

Parameters:

  • difficulty (String)

    the difficulty level.

Returns:

  • (String)

    the difficulty level (converted to a string).

See Also:



111
112
113
# File 'lib/sscharter/charter/metadata.rb', line 111

def difficulty difficulty
	@difficulty = difficulty.to_s
end

#difficulty_color(difficulty_color) ⇒ String

Set the color of the difficulty for the chart. This will be reflected in the return value of #to_sunniesnow.

The argument difficulty_color can be a color name (a key of COLORS), an RGB color in hexadecimal format (e.g. '#8c68f3', '#8CF'), an RGB color in decimal format (e.g. 'rgb(140, 104, 243)'), or an integer representing an RGB color (e.g. 0x8c68f3).

Parameters:

  • difficulty_color (Symbol, String, Integer)

    the color of the difficulty.

Returns:

  • (String)

    the color of the difficulty in hexadecimal format (e.g. '#8c68f3').

Raises:

  • (ArgumentError)

    if difficulty_color is not a valid color format.

See Also:



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/sscharter/charter/metadata.rb', line 84

def difficulty_color difficulty_color
	@difficulty_color = case difficulty_color
	when Symbol
		COLORS[difficulty_color]
	when /^#[0-9a-fA-F]{6}$/
		difficulty_color
	when /^#[0-9a-fA-F]{3}$/
		_, r, g, b = difficulty_color.chars
		"##{r}#{r}#{g}#{g}#{b}#{b}"
	when /^rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/
		r, g, b = $1, $2, $3
		sprintf '#%02x%02x%02x', r.to_i, g.to_i, b.to_i
	when Integer
		sprintf '#%06x', difficulty_color % 0x1000000
	else
		raise ArgumentError, 'unknown format of difficulty_color'
	end
end

#difficulty_name(difficulty_name) ⇒ String

Set the name of the difficulty for the chart. This will be reflected in the return value of #to_sunniesnow.

Parameters:

  • difficulty_name (String)

    the name of the difficulty.

Returns:

  • (String)

    the name of the difficulty, the same as the argument difficulty_name.

Raises:

  • (ArgumentError)

    if difficulty_name is not a String.

See Also:



68
69
70
71
# File 'lib/sscharter/charter/metadata.rb', line 68

def difficulty_name difficulty_name
	raise ArgumentError, 'difficulty_name must be a string' unless difficulty_name.is_a? String
	@difficulty_name = difficulty_name
end

#difficulty_sup(difficulty_sup) ⇒ String

Set the difficulty superscript for the chart. This will be reflected in the return value of #to_sunniesnow.

The argument difficulty_sup should be a string representing the difficulty superscript. Anything other than a string will be converted to a string using to_s.

Parameters:

  • difficulty_sup (String)

    the difficulty superscript.

Returns:

  • (String)

    the difficulty superscript (converted to a string).

See Also:



123
124
125
# File 'lib/sscharter/charter/metadata.rb', line 123

def difficulty_sup difficulty_sup
	@difficulty_sup = difficulty_sup.to_s
end

#drag(x, y) ⇒ Event Also known as: d

Creates a drag note at the given coordinates. The coordinates x and y must be numbers.

Technically, this adds an event of type :drag to the chart at the current time with properties containing the information provided by x and y.

Examples:

offset 0.1; bpm 120
d 0, 0
d 50, 0
# Now there are two drag notes at (0, 0) and (50, 0)

Parameters:

  • x (Numeric)

    the x-coordinate of the note.

  • y (Numeric)

    the y-coordinate of the note.

Returns:

  • (Event)

    the event representing the drag note.

Raises:

  • (ArgumentError)

    if x or y is not a number.



107
108
109
110
111
112
# File 'lib/sscharter/charter/basic_events.rb', line 107

def drag x, y
	if !x.is_a?(Numeric) || !y.is_a?(Numeric)
		raise ArgumentError, 'x and y must be numbers'
	end
	event :drag, x: x.to_f, y: y.to_f
end

#duplicate(events, new_tip_points: true) ⇒ Array<Event>

Duplicate all events in a given array. This method is useful when you want to duplicate a set of events. The argument events is an array of events to be duplicated. The argument new_tip_points is a boolean indicating whether to create new tip points. If it is true, new tip points will be created for the duplicated events. If it is false, each duplicated event shares the same tip point as the original event.

Examples:

Duplicate a note

offset 0.1; bpm 120
duplicate [t 0, 0]

Duplicate notes that share tip points with the original notes

offset 0.1; bpm 120
duplicate tp_chain(0, 100, 1) { t 0, 0 }

Parameters:

  • events (Array<Event>)

    the events to be duplicated.

  • new_tip_points (Boolean) (defaults to: true)

    whether to create new tip points for the duplicated events.

Returns:

  • (Array<Event>)

    the duplicated events.



139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/sscharter/charter/events_manip.rb', line 139

def duplicate events, new_tip_points: true
	result = []
	events.each do |event|
		next if event.type == :placeholder && !new_tip_points
		result.push event = event.dup
		if event[:tip_point] && new_tip_points
			event[:tip_point] = "#@current_duplicate #{event[:tip_point]}"
		end
		@groups.each { _1.push event }
	end
	@current_duplicate += 1 if new_tip_points
	result
end

#event(type, duration_beats = nil, **properties) ⇒ Event

Note:

Internal API.

Parameters:

  • type (Symbol)
  • duration_beats (Integer, Rational, nil) (defaults to: nil)
  • properties (Hash{Symbol => Numeric, String})

Returns:



384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
# File 'lib/sscharter/charter/event.rb', line 384

def event type, duration_beats = nil, **properties
	raise OffsetError.new __method__ unless @bpm_changes
	event = Event.new type, @current_beat, duration_beats, @bpm_changes, **properties
	@groups.each { _1.push event }
	return event unless event.tip_pointable?
	case @tip_point_mode_stack.last
	when :chain
		if @tip_point_start_to_add_stack.last
			@current_tip_point_stack[-1] = @tip_point_peak
			@tip_point_peak += 1
		end
		push_tip_point_start event
		@tip_point_start_to_add_stack[-1] = nil
	when :drop
		@current_tip_point_stack[-1] = @tip_point_peak
		@tip_point_peak += 1
		push_tip_point_start event
	when :none
		# pass
	end
	event
end

#flick(x, y, direction, text = '') ⇒ Event Also known as: f

Creates a flick note at the given coordinates with the given direction and text. The coordinates x and y must be numbers. The argument direction is the direction of the flick note in radians or a symbol. If it is a symbol, it should be one of the keys of DIRECTIONS (which are :right, :up_right, etc., abbreviated as :r, :ur etc.). If it is a number, it should be a number representing the angle in radians, specifying the angle rorated anticlockwise starting from the positive x-direction. The argument text is the text to be displayed on the note (it is converted to a string via to_s if it is not a string).

Technically, this adds an event of type :flick to the chart at the current time with properties containing the information provided by x, y, direction, and text.

Examples:

offset 0.1; bpm 120
f 0, 0, :r, 'Hello'
f 50, 0, Math::PI / 4, 'world'
# Now there are two flick notes at (0, 0) and (50, 0)
# with directions right and up right and texts 'Hello' and 'world' respectively

Parameters:

  • x (Numeric)

    the x-coordinate of the note.

  • y (Numeric)

    the y-coordinate of the note.

  • direction (Numeric, Symbol)

    the direction of the flick note in radians or a symbol.

  • text (String) (defaults to: '')

    the text to be displayed on the note.

Returns:

  • (Event)

    the event representing the flick note.

Raises:

  • (ArgumentError)

    if x or y is not a number, if direction is not a symbol or a number, or if the direction is a symbol that does not represent a known direction.



141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/sscharter/charter/basic_events.rb', line 141

def flick x, y, direction, text = ''
	if !x.is_a?(Numeric) || !y.is_a?(Numeric)
		raise ArgumentError, 'x and y must be numbers'
	end
	if direction.is_a? Symbol
		direction = DIRECTIONS[direction]
		raise ArgumentError, "unknown direction #{direction}" unless direction
	elsif direction.is_a? Numeric
		warn 'Are you using degrees as angle unit instead of radians?' if direction != 0 && direction % 45 == 0
		direction = direction.to_f
	else
		raise ArgumentError, 'direction must be a symbol or a number'
	end
	event :flick, x: x.to_f, y: y.to_f, angle: direction, text: text.to_s
end

#grid(duration_beats = 0) ⇒ Event

Creates a grid background pattern. The argument duration_beats is the duration of the background pattern in beats. It needs to be a non-negative Rational or Integer. If it is a Float, it will be converted to a Rational, and a warning will be issued.

Technically, this adds an event of type :grid to the chart at the current time with properties containing the information provided by duration_beats.

Examples:

offset 0.1; bpm 120
grid 1 # duration is 1
b 2
grid 2 # duration is 2

Parameters:

  • duration_beats (Rational, Integer) (defaults to: 0)

    the duration of the background pattern in beats.

Returns:

  • (Event)

    the event representing the background pattern.

Raises:

  • (ArgumentError)

    if duration_beats is not a number or is negative.



260
261
262
263
264
265
266
267
268
269
270
271
272
273
# File 'lib/sscharter/charter/basic_events.rb', line 260

%i[grid hexagon checkerboard diamond_grid pentagon turntable hexagram].each do |method_name|
	define_method method_name do |duration_beats = 0|
		unless duration_beats.is_a? Numeric
			raise ArgumentError, 'duration_beats must be a number'
		end
		if duration_beats < 0
			raise ArgumentError, 'duration must be non-negative'
		end
		if duration_beats.is_a? Float
			warn 'Rational is recommended over Float for duration_beats'
		end
		event method_name, duration_beats.to_r
	end
end

#group(preserve_beat: true, &block) ⇒ Array<Event>

Returns the events created inside block.

Returns:

  • (Array<Event>)

    the events created inside block.

Raises:

  • (ArgumentError)


91
92
93
94
95
96
97
98
99
# File 'lib/sscharter/charter/group.rb', line 91

def group preserve_beat: true, &block
	raise ArgumentError, 'no block given' unless block
	@groups.push result = []
	beat_backup = current_beat_state unless preserve_beat
	instance_eval &block
	restore_beat_state beat_backup unless preserve_beat
	@groups.delete_if { result.equal? _1 }
	result
end

#hexagon(duration_beats = 0) ⇒ Event

Creates a hexagon background pattern. The argument duration_beats is the duration of the background pattern in beats. It needs to be a non-negative Rational or Integer. If it is a Float, it will be converted to a Rational, and a warning will be issued.

Technically, this adds an event of type :hexagon to the chart at the current time with properties containing the information provided by duration_beats.

Examples:

offset 0.1; bpm 120
hexagon 1 # duration is 1
b 2
hexagon 2 # duration is 2

Parameters:

  • duration_beats (Rational, Integer) (defaults to: 0)

    the duration of the background pattern in beats.

Returns:

  • (Event)

    the event representing the background pattern.

Raises:

  • (ArgumentError)

    if duration_beats is not a number or is negative.



260
261
262
263
264
265
266
267
268
269
270
271
272
273
# File 'lib/sscharter/charter/basic_events.rb', line 260

%i[grid hexagon checkerboard diamond_grid pentagon turntable hexagram].each do |method_name|
	define_method method_name do |duration_beats = 0|
		unless duration_beats.is_a? Numeric
			raise ArgumentError, 'duration_beats must be a number'
		end
		if duration_beats < 0
			raise ArgumentError, 'duration must be non-negative'
		end
		if duration_beats.is_a? Float
			warn 'Rational is recommended over Float for duration_beats'
		end
		event method_name, duration_beats.to_r
	end
end

#hexagram(duration_beats = 0) ⇒ Event

Creates a hexagram background pattern. The argument duration_beats is the duration of the background pattern in beats. It needs to be a non-negative Rational or Integer. If it is a Float, it will be converted to a Rational, and a warning will be issued.

Technically, this adds an event of type :hexagram to the chart at the current time with properties containing the information provided by duration_beats.

Examples:

offset 0.1; bpm 120
hexagram 1 # duration is 1
b 2
hexagram 2 # duration is 2

Parameters:

  • duration_beats (Rational, Integer) (defaults to: 0)

    the duration of the background pattern in beats.

Returns:

  • (Event)

    the event representing the background pattern.

Raises:

  • (ArgumentError)

    if duration_beats is not a number or is negative.



260
261
262
263
264
265
266
267
268
269
270
271
272
273
# File 'lib/sscharter/charter/basic_events.rb', line 260

%i[grid hexagon checkerboard diamond_grid pentagon turntable hexagram].each do |method_name|
	define_method method_name do |duration_beats = 0|
		unless duration_beats.is_a? Numeric
			raise ArgumentError, 'duration_beats must be a number'
		end
		if duration_beats < 0
			raise ArgumentError, 'duration must be non-negative'
		end
		if duration_beats.is_a? Float
			warn 'Rational is recommended over Float for duration_beats'
		end
		event method_name, duration_beats.to_r
	end
end

#hold(x, y, duration_beats, text = '') ⇒ Event Also known as: h

Creates a hold note at the given coordinates with the given duration and text. The coordinates x and y must be numbers. The argument duration_beats is the duration of the hold note in beats. It needs to be a positive Rational or Integer. If it is a Float, it will be converted to a Rational, and a warning will be issued. The argument text is the text to be displayed on the note (it is converted to a string via to_s if it is not a string).

Technically, this adds an event of type :hold to the chart at the current time with properties containing the information provided by x, y, duration_beats, and text.

Examples:

offset 0.1; bpm 120
h 0, 0, 1, 'Hello'
h 50, 0, 2, 'world'
# Now there are two hold notes at (0, 0) and (50, 0)
# with durations 1 and 2 beats and texts 'Hello' and 'world' respectively

Parameters:

  • x (Numeric)

    the x-coordinate of the note.

  • y (Numeric)

    the y-coordinate of the note.

  • duration_beats (Rational, Integer)

    the duration of the hold note in beats.

  • text (String) (defaults to: '')

    the text to be displayed on the note.

Returns:

  • (Event)

    the event representing the hold note.

Raises:

  • (ArgumentError)

    if x, y, or duration_beats is not a number, or if duration_beats is not positive.



79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/sscharter/charter/basic_events.rb', line 79

def hold x, y, duration_beats, text = ''
	if !x.is_a?(Numeric) || !y.is_a?(Numeric) || !duration_beats.is_a?(Numeric)
		raise ArgumentError, 'x, y, and duration must be numbers'
	end
	if duration_beats <= 0
		raise ArgumentError, 'duration must be positive'
	end
	if duration_beats.is_a? Float
		warn 'Rational is recommended over Float for duration_beats'
	end
	event :hold, duration_beats.to_r, x: x.to_f, y: y.to_f, text: text.to_s
end

#image(filename, x, y, duration_beats, width, height = nil, above: nil, coordinate_system: nil, mirrorable: nil) ⇒ Event

Creates an image event.

Parameters:

  • filename (String)
  • x (Numeric)
  • y (Numeric)
  • duration_beats (Integer, Rational)
  • width (Numeric)
  • height (Numeric?) (defaults to: nil)
  • above (IMAGE_LAYER_ABOVE_SET?) (defaults to: nil)
  • coordinate_system (COORDINATE_SYSTEMS_SET?) (defaults to: nil)
  • mirrorable (Boolean?) (defaults to: nil)

Returns:

Raises:

  • (ArgumentError)


30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/sscharter/charter/story_events.rb', line 30

def image filename, x, y, duration_beats, width, height = nil, above: nil, coordinate_system: nil, mirrorable: nil
	raise ArgumentError, 'filename must be a string' unless filename.is_a? String
	raise ArgumentError, 'x and y must be numbers' unless x.is_a?(Numeric) && y.is_a?(Numeric)
	raise ArgumentError, 'duration_beats must be a number' unless duration_beats.is_a? Numeric
	raise ArgumentError, 'duration_beats must be non-negative' if duration_beats < 0
	raise ArgumentError, 'width must be a number' unless width.is_a? Numeric
	raise ArgumentError, 'height must be a number' if !height.nil? && !height.is_a?(Numeric)
	raise ArgumentError, "unknown coordinate_system #{coordinate_system}" if !coordinate_system.nil? && !%i[chart screen].include?(coordinate_system)
	warn 'Rational is recommended over Float for duration_beats' if duration_beats.is_a? Float
	raise ArgumentError, "invalid above: #{above}" if !above.nil? && !IMAGE_LAYER_ABOVE_SET.include?(above)
	raise ArgumentError, "invalid coordinate_system: #{coordinate_system}" if !coordinate_system.nil? && !COORDINATE_SYSTEMS_SET.include?(coordinate_system)
	raise ArgumentError, "mirrorable must be a boolean" unless [nil, true, false].include? mirrorable
	additional_properties = {}
	additional_properties[:above] = above.snake_to_camel if above
	additional_properties[:coordinate_system] = coordinate_system.snake_to_camel if coordinate_system
	additional_properties[:mirrorable] = mirrorable unless mirrorable.nil?
	additional_properties[:height] = height.to_f if height
	event :image, duration_beats.to_r, filename: filename, x: x.to_f, y: y.to_f, width: width.to_f, **additional_properties
end

#init_beat_statevoid

Note:

Internal API.

This method returns an undefined value.



296
297
298
299
# File 'lib/sscharter/charter/beat.rb', line 296

def init_beat_state
	@current_beat = nil
	@bpm_changes = nil
end

#init_bookmarksvoid

Note:

Internal API.

This method returns an undefined value.



41
42
43
44
# File 'lib/sscharter/charter/group.rb', line 41

def init_bookmarks
	@bookmarks = {}
	nil
end

#init_chart_infovoid

Note:

Internal API.

This method returns an undefined value.



16
17
18
19
20
21
22
23
24
25
# File 'lib/sscharter/charter/metadata.rb', line 16

def init_chart_info
	@difficulty_name = ''
	@difficulty_color = '#000000'
	@difficulty = ''
	@difficulty_sup = ''
	@title = ''
	@artist = ''
	@charter = ''
	@events = []
end

#init_group_statevoid

Note:

Internal API.

This method returns an undefined value.



48
49
50
51
52
53
54
55
56
57
58
# File 'lib/sscharter/charter/group.rb', line 48

def init_group_state
	@tip_point_mode_stack = [:none]
	@current_tip_point_stack = []
	@current_tip_point_group_stack = []
	@tip_point_peak = 0
	@current_duplicate = 0
	@tip_point_start_stack = [nil]
	@tip_point_start_to_add_stack = [nil]
	@groups = [@events]
	nil
end

#inspectString

Returns:

  • (String)


73
74
75
# File 'lib/sscharter/charter.rb', line 73

def inspect
	"#<Sunniesnow::Charter #@name>"
end

#mark(name) ⇒ Object

Returns name.

Parameters:

  • name (Object)

Returns:

  • (Object)

    name.



103
104
105
106
# File 'lib/sscharter/charter/group.rb', line 103

def mark name
	@bookmarks[name] = Bookmark.new current_beat_state, current_group_state
	name
end

#offset(offset) ⇒ BpmChangeList

Set the offset. This is the time in seconds of the zeroth beat. This method must be called before any other methods that require a beat, or an OffsetError will be raised.

After calling this method, the current beat (see Sunniesnow::Charter::BeatSeries#beat and Sunniesnow::Charter::BeatSeries#beat!) is set to zero, and a new BPM needs to be set using Sunniesnow::Charter::BeatSeries#bpm. Only after that can the time of any positive beat be calculated.

Though not commonly useful, this method can be called multiple times in a chart. A new call of this method does not affect the events and BPM changes set before. Technically, each event is associated with a BPM change list (see Sunniesnow::Charter::Metronomic#bpm_changes), and each call of this method creates a new BPM change list, which is used for the events set after.

Examples:

offset 0.1
p time_at # Outputs 0.1, which is the offset
offset 0.2
p time_at # Outputs 0.2, which is the updated offset by the second call

Parameters:

  • offset (Numeric)

    the offset in seconds.

Returns:

Raises:

  • (ArgumentError)

    if offset is not a number.

See Also:



326
327
328
329
330
# File 'lib/sscharter/charter/beat.rb', line 326

def offset offset
	raise ArgumentError, 'offset must be a number' unless offset.is_a? Numeric
	@current_beat = 0r
	@bpm_changes = BpmChangeList.new offset.to_f
end

#output_json(*args, **opts) ⇒ String

Returns:

  • (String)


68
69
70
# File 'lib/sscharter/charter.rb', line 68

def output_json *args, **opts
	to_sunniesnow(**opts).to_json *args
end

#pentagon(duration_beats = 0) ⇒ Event

Creates a pentagon background pattern. The argument duration_beats is the duration of the background pattern in beats. It needs to be a non-negative Rational or Integer. If it is a Float, it will be converted to a Rational, and a warning will be issued.

Technically, this adds an event of type :pentagon to the chart at the current time with properties containing the information provided by duration_beats.

Examples:

offset 0.1; bpm 120
pentagon 1 # duration is 1
b 2
pentagon 2 # duration is 2

Parameters:

  • duration_beats (Rational, Integer) (defaults to: 0)

    the duration of the background pattern in beats.

Returns:

  • (Event)

    the event representing the background pattern.

Raises:

  • (ArgumentError)

    if duration_beats is not a number or is negative.



260
261
262
263
264
265
266
267
268
269
270
271
272
273
# File 'lib/sscharter/charter/basic_events.rb', line 260

%i[grid hexagon checkerboard diamond_grid pentagon turntable hexagram].each do |method_name|
	define_method method_name do |duration_beats = 0|
		unless duration_beats.is_a? Numeric
			raise ArgumentError, 'duration_beats must be a number'
		end
		if duration_beats < 0
			raise ArgumentError, 'duration must be non-negative'
		end
		if duration_beats.is_a? Float
			warn 'Rational is recommended over Float for duration_beats'
		end
		event method_name, duration_beats.to_r
	end
end

#push_tip_point_start(start_event) ⇒ void

Note:

Internal API.

This method returns an undefined value.

Parameters:



95
96
97
98
99
100
101
102
103
104
# File 'lib/sscharter/charter/tip_point.rb', line 95

def push_tip_point_start start_event
	start_event[:tip_point] = @current_tip_point_stack.last.to_s
	tip_point_start = @tip_point_start_to_add_stack.last&.get_start_placeholder start_event
	return unless tip_point_start
	@groups.each do |group|
		group.push tip_point_start
		break if group.equal?(@current_tip_point_group_stack.last) && @tip_point_mode_stack.last != :drop
	end
	nil
end

#remove(*events) ⇒ Array<Event>

Remove events from the chart.

Parameters:

Returns:



169
170
171
# File 'lib/sscharter/charter/events_manip.rb', line 169

def remove *events
	events.each { |event| @groups.each { _1.delete event } }
end

#restore_group_state(backup) ⇒ void

Note:

Internal API.

This method returns an undefined value.

Parameters:



77
78
79
80
81
82
83
84
85
# File 'lib/sscharter/charter/group.rb', line 77

def restore_group_state backup
	@tip_point_mode_stack = backup.tip_point_mode_stack
	@current_tip_point_stack = backup.current_tip_point_stack
	@current_tip_point_group_stack = backup.current_tip_point_group_stack
	@current_duplicate = backup.current_duplicate
	@tip_point_start_to_add_stack = backup.tip_point_start_to_add_stack
	@groups = backup.groups
	nil
end

#tap(x, y, text = '') ⇒ Event Also known as: t

Creates a tap note at the given coordinates with the given text. The coordinates x and y must be numbers. The argument text is the text to be displayed on the note (it is converted to a string via to_s if it is not a string).

Technically, this adds an event of type :tap to the chart at the current time with properties containing the information provided by x, y, and text.

Examples:

offset 0.1; bpm 120
t 0, 0, 'Hello'
t 50, 0, 'world'
# Now there are two simultaneous tap notes at (0, 0) and (50, 0)
# with texts 'Hello' and 'world' respectively

Parameters:

  • x (Numeric)

    the x-coordinate of the note.

  • y (Numeric)

    the y-coordinate of the note.

  • text (String) (defaults to: '')

    the text to be displayed on the note.

Returns:

  • (Event)

    the event representing the tap note.

Raises:

  • (ArgumentError)

    if x or y is not a number.



48
49
50
51
52
53
# File 'lib/sscharter/charter/basic_events.rb', line 48

def tap x, y, text = ''
	if !x.is_a?(Numeric) || !y.is_a?(Numeric)
		raise ArgumentError, 'x and y must be numbers'
	end
	event :tap, x: x.to_f, y: y.to_f, text: text.to_s
end

#time_dependent(events, goto_beat: true, preserve_beat: false, &block) ⇒ Array<Event> Also known as: td

Parameters:

  • events (Array<Event>, Event)
  • goto_beat (Boolean) (defaults to: true)
  • preserve_beat (Boolean) (defaults to: false)

Returns:

Raises:

  • (ArgumentError)


414
415
416
417
418
419
420
421
422
423
424
# File 'lib/sscharter/charter/event.rb', line 414

def time_dependent events, goto_beat: true, preserve_beat: false, &block
	raise ArgumentError, 'no block given' unless block
	events = [events] if events.is_a? Event
	beat_backup = current_beat_state if !goto_beat || !preserve_beat
	events.each do |event|
		event.time_dependent.restore_beat_state goto_beat ? event.beat_state : beat_backup
		event.time_dependent.instance_eval &block
	end
	restore_beat_state preserve_beat ? events.last.time_dependent.current_beat_state : beat_backup
	events
end

#tip_point(mode, *args, preserve_beat: true, **opts, &block) ⇒ Object

Note:

Internal API.



108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/sscharter/charter/tip_point.rb', line 108

def tip_point mode, *args, preserve_beat: true, **opts, &block
	@tip_point_mode_stack.push mode
	if mode == :none
		@tip_point_start_stack.push nil
		@tip_point_start_to_add_stack.push nil
		@current_tip_point_stack.push nil
	else
		if args.empty? && opts.empty?
			unless @tip_point_start_stack.last
				raise ArgumentError, 'cannot omit tip point arguments at top level or inside tip_point_none'
			end
			@tip_point_start_stack.push @tip_point_start_stack.last.dup
		else
			@tip_point_start_stack.push TipPointStart.new *args, **opts
		end
		@tip_point_start_to_add_stack.push @tip_point_start_stack.last
		@current_tip_point_stack.push nil
	end
	result = group preserve_beat: preserve_beat do
		@current_tip_point_group_stack.push @groups.last
		instance_eval &block
	end
	@tip_point_start_stack.pop
	@tip_point_start_to_add_stack.pop
	@tip_point_mode_stack.pop
	@current_tip_point_stack.pop
	@current_tip_point_group_stack.pop
	result
end

#tip_point_chain(x, y, relative_time, relative: true, preserve_beat: true, &block) ⇒ Array<Event> #tip_point_chain(x, y, speed:, relative: true, preserve_beat: true, &block) ⇒ Array<Event> #tip_point_chain(x, y, relative_beat:, relative: true, preserve_beat: true, &block) ⇒ Array<Event> #tip_point_chain(x, y, beat_speed:, relative: true, preserve_beat: true, &block) ⇒ Array<Event> #tip_point_chain(preserve_beat: true, &block) ⇒ Array<Event> Also known as: tp_chain

Create a tip point to connect the notes created inside block. There are four overloads of this method for different ways to specify the time at which the tip point appears, and there is another overload that totally omits the arguments for specifying when and where the tip point appears and can only be used inside another tip point block. This method is otherwise the same as #group.

If the methods #tp_chain, #tp_drop, and #tp_none are nested in block, only the innermost one takes effect.

Examples:

Nested tip points

offset 0.1; bpm 120
tp_chain 0, 100, 1 do
  t 0, 0, 'A'; b 1 # tip point from above
  tp_drop -100, 0, 1 do
    t 25, 25, 'B'; b 1 # tip point from left
    t 50, 25, 'C'; b 1 # tip point from left
  end
  tp_none do
    t 75, 50, 'D'; b 1 # no tip point
  end
  t 100, 0, 'E'; b 1 # same tip point as note A
end

Overloads:

  • #tip_point_chain(x, y, relative_time, relative: true, preserve_beat: true, &block) ⇒ Array<Event>

    The time at which a created tip point appears is the time of the first note it visits minus relative_time.

    Parameters:

    • relative_time (Numeric)
  • #tip_point_chain(x, y, speed:, relative: true, preserve_beat: true, &block) ⇒ Array<Event>

    The time at which a created tip point appears is the time of the first note it visits minus the distance between the note and the position where the tip point appears divided by speed.

    Parameters:

    • speed (Numeric)
  • #tip_point_chain(x, y, relative_beat:, relative: true, preserve_beat: true, &block) ⇒ Array<Event>

    The beat at which a created tip point appears is the beat of the first note it visits minus relative_beat.

    Parameters:

    • relative_beat (Rational, Integer)
  • #tip_point_chain(x, y, beat_speed:, relative: true, preserve_beat: true, &block) ⇒ Array<Event>

    The beat at which a created tip point appears is the beat of the first note it visits minus the distance between the note and the position where the tip point appears divided by beat_speed.

    Parameters:

    • beat_speed (Numeric)
  • #tip_point_chain(preserve_beat: true, &block) ⇒ Array<Event>

    This overload can only be used inside another tip point block, and it creates a tip point with the same parameters as the one created by the outer block.

Parameters:

  • preserve_beat (Boolean) (defaults to: true)

    whether the Sunniesnow::Charter::BeatSeries#current_beat will be reset to the value before executing block after it is executed.

  • relative (Boolean) (defaults to: true)

    whether the position at which a created tip point appears specified by the arguments x and y is relative to the first note it visits or absolute.

  • x (Numeric)

    the x-coordinate of the position at which a created tip point appears, whether relative or absolute.

  • y (Numeric)

    the y-coordinate of the position at which a created tip point appears, whether relative or absolute.

Returns:

  • (Array<Event>)

    the events created inside block, similar to #group.

Raises:

  • (ArgumentError)


199
200
201
202
203
204
# File 'lib/sscharter/charter/tip_point.rb', line 199

%i[chain drop none].each do |mode|
	define_method "tip_point_#{mode}" do |*args, **opts, &block|
		tip_point mode, *args, **opts, &block
	end
	alias_method "tp_#{mode}", "tip_point_#{mode}"
end

#tip_point_drop(x, y, relative_time, relative: true, preserve_beat: true, &block) ⇒ Array<Event> #tip_point_drop(x, y, speed:, relative: true, preserve_beat: true, &block) ⇒ Array<Event> #tip_point_drop(x, y, relative_beat:, relative: true, preserve_beat: true, &block) ⇒ Array<Event> #tip_point_drop(x, y, beat_speed:, relative: true, preserve_beat: true, &block) ⇒ Array<Event> #tip_point_drop(preserve_beat: true, &block) ⇒ Array<Event> Also known as: tp_drop

A tip point is created for each note created inside block. There are four overloads of this method for different ways to specify the time at which the tip point appears, and there is another overload that totally omits the arguments for specifying when and where the tip point appears and can only be used inside another tip point block. This method is otherwise the same as #group.

If the methods #tp_chain, #tp_drop, and #tp_none are nested in block, only the innermost one takes effect.

Examples:

Nested tip points

offset 0.1; bpm 120
tp_chain 0, 100, 1 do
  t 0, 0, 'A'; b 1 # tip point from above
  tp_drop -100, 0, 1 do
    t 25, 25, 'B'; b 1 # tip point from left
    t 50, 25, 'C'; b 1 # tip point from left
  end
  tp_none do
    t 75, 50, 'D'; b 1 # no tip point
  end
  t 100, 0, 'E'; b 1 # same tip point as note A
end

Overloads:

  • #tip_point_drop(x, y, relative_time, relative: true, preserve_beat: true, &block) ⇒ Array<Event>

    The time at which a created tip point appears is the time of the first note it visits minus relative_time.

    Parameters:

    • relative_time (Numeric)
  • #tip_point_drop(x, y, speed:, relative: true, preserve_beat: true, &block) ⇒ Array<Event>

    The time at which a created tip point appears is the time of the first note it visits minus the distance between the note and the position where the tip point appears divided by speed.

    Parameters:

    • speed (Numeric)
  • #tip_point_drop(x, y, relative_beat:, relative: true, preserve_beat: true, &block) ⇒ Array<Event>

    The beat at which a created tip point appears is the beat of the first note it visits minus relative_beat.

    Parameters:

    • relative_beat (Rational, Integer)
  • #tip_point_drop(x, y, beat_speed:, relative: true, preserve_beat: true, &block) ⇒ Array<Event>

    The beat at which a created tip point appears is the beat of the first note it visits minus the distance between the note and the position where the tip point appears divided by beat_speed.

    Parameters:

    • beat_speed (Numeric)
  • #tip_point_drop(preserve_beat: true, &block) ⇒ Array<Event>

    This overload can only be used inside another tip point block, and it creates a tip point with the same parameters as the one created by the outer block.

Parameters:

  • preserve_beat (Boolean) (defaults to: true)

    whether the Sunniesnow::Charter::BeatSeries#current_beat will be reset to the value before executing block after it is executed.

  • relative (Boolean) (defaults to: true)

    whether the position at which a created tip point appears specified by the arguments x and y is relative to the first note it visits or absolute.

  • x (Numeric)

    the x-coordinate of the position at which a created tip point appears, whether relative or absolute.

  • y (Numeric)

    the y-coordinate of the position at which a created tip point appears, whether relative or absolute.

Returns:

  • (Array<Event>)

    the events created inside block, similar to #group.

Raises:

  • (ArgumentError)


199
200
201
202
203
204
# File 'lib/sscharter/charter/tip_point.rb', line 199

%i[chain drop none].each do |mode|
	define_method "tip_point_#{mode}" do |*args, **opts, &block|
		tip_point mode, *args, **opts, &block
	end
	alias_method "tp_#{mode}", "tip_point_#{mode}"
end

#tip_point_none(preserve_beat: true, &block) ⇒ Array<Event> Also known as: tp_none

Notes created inside block will not be visited by any tip point. This method is otherwise the same as #group.

Returns:

  • (Array<Event>)

    the events created inside block, similar to #group.



199
200
201
202
203
204
# File 'lib/sscharter/charter/tip_point.rb', line 199

%i[chain drop none].each do |mode|
	define_method "tip_point_#{mode}" do |*args, **opts, &block|
		tip_point mode, *args, **opts, &block
	end
	alias_method "tp_#{mode}", "tip_point_#{mode}"
end

#title(title) ⇒ String

Set the title of the music for the chart. This will be reflected in the return value of #to_sunniesnow.

Parameters:

  • title (String)

    the title of the music.

Returns:

  • (String)

    the title of the music, the same as the argument title.

Raises:

  • (ArgumentError)

    if title is not a String.

See Also:



35
36
37
38
# File 'lib/sscharter/charter/metadata.rb', line 35

def title title
	raise ArgumentError, 'title must be a string' unless title.is_a? String
	@title = title
end

#to_sunniesnow(live_reload_port: 31108, production: false) ⇒ Sunniesnow::Chart

See Sunniesnow::Chart#initialize for the arguments.

Returns:



54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/sscharter/charter.rb', line 54

def to_sunniesnow **opts
	result = Sunniesnow::Chart.new **opts
	result.title = @title
	result.artist = @artist
	result.charter = @charter
	result.difficulty_name = @difficulty_name
	result.difficulty_color = @difficulty_color
	result.difficulty = @difficulty
	result.difficulty_sup = @difficulty_sup
	@events.each { result.events.push _1.to_sunniesnow }
	result
end

#transform(events, &block) ⇒ Array<Event>

Transform all events in a given array in time and/or space. Space transformation does not affect background patterns.

Parameters:

Returns:

Raises:

  • (ArgumentError)


158
159
160
161
162
163
164
# File 'lib/sscharter/charter/events_manip.rb', line 158

def transform events, &block
	raise ArgumentError, 'no block given' unless block
	events = [events] if events.is_a? Event
	transform = Transform.new
	transform.instance_eval &block
	events.each { transform.apply _1 }
end

#turntable(duration_beats = 0) ⇒ Event

Creates a turntable background pattern. The argument duration_beats is the duration of the background pattern in beats. It needs to be a non-negative Rational or Integer. If it is a Float, it will be converted to a Rational, and a warning will be issued.

Technically, this adds an event of type :turntable to the chart at the current time with properties containing the information provided by duration_beats.

Examples:

offset 0.1; bpm 120
turntable 1 # duration is 1
b 2
turntable 2 # duration is 2

Parameters:

  • duration_beats (Rational, Integer) (defaults to: 0)

    the duration of the background pattern in beats.

Returns:

  • (Event)

    the event representing the background pattern.

Raises:

  • (ArgumentError)

    if duration_beats is not a number or is negative.



260
261
262
263
264
265
266
267
268
269
270
271
272
273
# File 'lib/sscharter/charter/basic_events.rb', line 260

%i[grid hexagon checkerboard diamond_grid pentagon turntable hexagram].each do |method_name|
	define_method method_name do |duration_beats = 0|
		unless duration_beats.is_a? Numeric
			raise ArgumentError, 'duration_beats must be a number'
		end
		if duration_beats < 0
			raise ArgumentError, 'duration must be non-negative'
		end
		if duration_beats.is_a? Float
			warn 'Rational is recommended over Float for duration_beats'
		end
		event method_name, duration_beats.to_r
	end
end