summaryrefslogtreecommitdiffhomepage
path: root/dragon
diff options
context:
space:
mode:
authorAmir Rajan <[email protected]>2021-09-06 14:32:04 -0500
committerAmir Rajan <[email protected]>2021-09-06 14:34:34 -0500
commit2f5eb6ab368b062dbbde39b3cee6eae23c5452ff (patch)
treee2f0b5f4a1ab4919cf5669f6187994489411821a /dragon
parentaa8d3ac4bdccf522b8082a7fa7d595be2bd54b7d (diff)
downloaddragonruby-game-toolkit-contrib-2f5eb6ab368b062dbbde39b3cee6eae23c5452ff.tar.gz
dragonruby-game-toolkit-contrib-2f5eb6ab368b062dbbde39b3cee6eae23c5452ff.zip
Synced with version 2.26
Diffstat (limited to 'dragon')
-rw-r--r--dragon/args.rb17
-rw-r--r--dragon/console.rb12
-rw-r--r--dragon/framerate.rb7
-rw-r--r--dragon/recording.rb260
-rw-r--r--dragon/tweetcart.rb102
5 files changed, 391 insertions, 7 deletions
diff --git a/dragon/args.rb b/dragon/args.rb
index 9cf6e33..5bb0ccf 100644
--- a/dragon/args.rb
+++ b/dragon/args.rb
@@ -200,5 +200,22 @@ module GTK
def autocomplete_methods
[:inputs, :outputs, :gtk, :state, :geometry, :audio, :grid, :layout, :fn]
end
+
+ def method_missing name, *args, &block
+ if (args.length <= 1) && (@state.as_hash.key? name)
+ raise <<-S
+* ERROR - :#{name} method missing on ~#{self.class.name}~.
+The method
+ :#{name}
+with args
+ #{args}
+doesn't exist on #{inspect}.
+** POSSIBLE SOLUTION - ~args.state.#{name}~ exists.
+Did you forget ~.state~ before ~.#{name}~?
+S
+ end
+
+ super
+ end
end
end
diff --git a/dragon/console.rb b/dragon/console.rb
index b3a2c2a..34183ae 100644
--- a/dragon/console.rb
+++ b/dragon/console.rb
@@ -434,6 +434,7 @@ S
if console_toggle_key_down? args
args.inputs.text.clear
toggle
+ args.inputs.keyboard.clear if !@visible
end
return unless visible?
@@ -445,7 +446,16 @@ S
@log_offset = 0 if @log_offset < 0
if args.inputs.keyboard.key_down.enter
- eval_the_set_command
+ if slide_progress > 0.5
+ # in the event of an exception, the console window pops up
+ # and is pre-filled with $gtk.reset.
+ # there is an annoying scenario where the exception could be thrown
+ # by pressing enter (while playing the game). if you press enter again
+ # quickly, then the game is reset which closes the console.
+ # so enter in the console is only evaluated if the slide_progress
+ # is atleast half way down the page.
+ eval_the_set_command
+ end
elsif args.inputs.keyboard.key_down.v
if args.inputs.keyboard.key_down.control || args.inputs.keyboard.key_down.meta
prompt << $gtk.ffi_misc.getclipboard
diff --git a/dragon/framerate.rb b/dragon/framerate.rb
index a9504a6..ff2f1c5 100644
--- a/dragon/framerate.rb
+++ b/dragon/framerate.rb
@@ -35,12 +35,7 @@ module GTK
if framerate_below_threshold?
@last_framerate = current_framerate
- if !@framerate_important_notification_happened
- log_important framerate_warning_message
- else
- log framerate_warning_message
- end
- @framerate_important_notification_happened = true
+ log framerate_warning_message
end
end
diff --git a/dragon/recording.rb b/dragon/recording.rb
new file mode 100644
index 0000000..72d8da9
--- /dev/null
+++ b/dragon/recording.rb
@@ -0,0 +1,260 @@
+# coding: utf-8
+# Copyright 2019 DragonRuby LLC
+# MIT License
+# recording.rb has been released under MIT (*only this file*).
+
+module GTK
+ # FIXME: Gross
+ # @gtk
+ class Replay
+ # @gtk
+ def self.start file_name = nil
+ $recording.start_replay file_name
+ end
+
+ # @gtk
+ def self.stop
+ $recording.stop_replay
+ end
+ end
+
+ # @gtk
+ class Recording
+ def initialize runtime
+ @runtime = runtime
+ @tick_count = 0
+ @global_input_order = 1
+ end
+
+ def tick
+ @tick_count += 1
+ end
+
+ def start_recording seed_number = nil
+ if !seed_number
+ log <<-S
+* ERROR:
+To start recording, you must provide an integer value to
+seed random number generation.
+S
+ $console.set_command "$recording.start SEED_NUMBER"
+ return
+ end
+
+ if @is_recording
+ log <<-S
+* ERROR:
+You are already recording, first cancel (or stop) the current recording.
+S
+ $console.set_command "$recording.cancel"
+ return
+ end
+
+ if @is_replaying
+ log <<-S
+* ERROR:
+You are currently replaying a recording, first stop the replay.
+S
+ return
+ end
+
+ log_info <<-S
+Recording has begun with RNG seed value set to #{seed_number}.
+To stop recording use stop_recording(filename).
+The recording will stop without saving a file if a filename is nil.
+S
+
+ $console.set_command "$recording.stop 'replay.txt'"
+ @runtime.__reset__
+ @seed_number = seed_number
+ @runtime.set_rng seed_number
+
+ @tick_count = 0
+ @global_input_order = 1
+ @is_recording = true
+ @input_history = []
+ @runtime.notify! "Recording started. When completed, open the console to save it using $recording.stop FILE_NAME (or cancel).", 300
+ end
+
+ # @gtk
+ def start seed_number = nil
+ start_recording seed_number
+ end
+
+ def is_replaying?
+ @is_replaying
+ end
+
+ def is_recording?
+ @is_recording
+ end
+
+ # @gtk
+ def stop file_name = nil
+ stop_recording file_name
+ end
+
+ # @gtk
+ def cancel
+ stop_recording_core
+ @runtime.notify! "Recording cancelled."
+ end
+
+ def stop_recording file_name = nil
+ if !file_name
+ log <<-S
+* ERROR:
+To please specify a file name when calling:
+$recording.stop FILE_NAME
+
+If you do NOT want to save the recording, call:
+$recording.cancel
+S
+ $console.set_command "$recording.stop 'replay.txt'"
+ return
+ end
+
+ if !@is_recording
+ log_info "You are not currently recording. Use start_recording(seed_number) to start recording."
+ $console.set_command "$recording.start"
+ return
+ end
+
+ if file_name
+ text = "replay_version 2.0\n"
+ text << "stopped_at #{@tick_count}\n"
+ text << "seed #{@seed_number}\n"
+ text << "recorded_at #{Time.now.to_s}\n"
+ @input_history.each do |items|
+ text << "#{items}\n"
+ end
+ @runtime.write_file file_name, text
+ @runtime.write_file 'last_replay.txt', text
+ log_info "The recording has been saved successfully at #{file_name}. You can use start_replay(\"#{file_name}\") to replay the recording."
+ end
+
+ $console.set_command "$replay.start '#{file_name}'"
+ stop_recording_core
+ @runtime.notify! "Recording saved to #{file_name}. To replay it: $replay.start \"#{file_name}\"."
+ log_info "You can run the replay later on startup using: ./dragonruby mygame --replay #{@replay_file_name}"
+ nil
+ end
+
+ def stop_recording_core
+ @is_recording = false
+ @input_history = nil
+ @last_history = nil
+ @runtime.__reset__
+ end
+
+ def start_replay file_name = nil
+ if !file_name
+ log <<-S
+* ERROR:
+Please provide a file name to $recording.start.
+S
+ $console.set_command "$replay.start 'replay.txt'"
+ return
+ end
+
+ text = @runtime.read_file file_name
+ return false unless text
+
+ if text.each_line.first.strip != "replay_version 2.0"
+ raise "The replay file #{file_name} is not compatible with this version of DragonRuby Game Toolkit. Please recreate the replay (sorry)."
+ end
+
+ @replay_file_name = file_name
+
+ $replay_data = { input_history: { } }
+ text.each_line do |l|
+ if l.strip.length == 0
+ next
+ elsif l.start_with? 'replay_version'
+ next
+ elsif l.start_with? 'seed'
+ $replay_data[:seed] = l.split(' ').last.to_i
+ elsif l.start_with? 'stopped_at'
+ $replay_data[:stopped_at] = l.split(' ').last.to_i
+ elsif l.start_with? 'recorded_at'
+ $replay_data[:recorded_at] = l.split(' ')[1..-1].join(' ')
+ elsif l.start_with? '['
+ name, value_1, value_2, value_count, id, tick_count = l.strip.gsub('[', '').gsub(']', '').split(',')
+ $replay_data[:input_history][tick_count.to_i] ||= []
+ $replay_data[:input_history][tick_count.to_i] << {
+ id: id.to_i,
+ name: name.gsub(':', '').to_sym,
+ value_1: value_1.to_f,
+ value_2: value_2.to_f,
+ value_count: value_count.to_i
+ }
+ else
+ raise "Replay data seems corrupt. I don't know how to parse #{l}."
+ end
+ end
+
+ $replay_data[:input_history].keys.each do |key|
+ $replay_data[:input_history][key] = $replay_data[:input_history][key].sort_by {|input| input[:id]}
+ end
+
+ @runtime.__reset__
+ @runtime.set_rng $replay_data[:seed]
+ @tick_count = 0
+ @is_replaying = true
+ log_info "Replay has been started."
+ @runtime.notify! "Replay started [#{@replay_file_name}]."
+ end
+
+ def stop_replay notification_message = "Replay has been stopped."
+ if !is_replaying?
+ log <<-S
+* ERROR:
+No replay is currently running. Call $replay.start FILE_NAME to start a replay.
+S
+
+ $console.set_command "$replay.start 'replay.txt'"
+ return
+ end
+ log_info notification_message
+ @is_replaying = false
+ $replay_data = nil
+ @tick_count = 0
+ @global_input_order = 1
+ $console.set_command_silent "$replay.start '#{@replay_file_name}'"
+ @runtime.__reset__
+ @runtime.notify! notification_message
+ end
+
+ def record_input_history name, value_1, value_2, value_count, clear_cache = false
+ return if @is_replaying
+ return unless @is_recording
+ @input_history << [name, value_1, value_2, value_count, @global_input_order, @tick_count]
+ @global_input_order += 1
+ end
+
+ def stage_replay_values
+ return unless @is_replaying
+ return unless $replay_data
+
+ if $replay_data[:stopped_at] <= @tick_count
+ stop_replay "Replay completed [#{@replay_file_name}]. To rerun, bring up the Console and press enter."
+ return
+ end
+
+ inputs_this_tick = $replay_data[:input_history][@tick_count]
+
+ if @tick_count.zmod? 60
+ log_info "Replay ends in #{($replay_data[:stopped_at] - @tick_count).idiv 60} second(s)."
+ end
+
+ return unless inputs_this_tick
+ inputs_this_tick.each do |v|
+ args = []
+ args << v[:value_1] if v[:value_count] >= 1
+ args << v[:value_2] if v[:value_count] >= 2
+ args << :replay
+ $gtk.send v[:name], *args
+ end
+ end
+ end
+end
diff --git a/dragon/tweetcart.rb b/dragon/tweetcart.rb
new file mode 100644
index 0000000..9e278b3
--- /dev/null
+++ b/dragon/tweetcart.rb
@@ -0,0 +1,102 @@
+# coding: utf-8
+# Copyright 2019 DragonRuby LLC
+# MIT License
+# tweetcart.rb has been released under MIT (*only this file*).
+
+def $top_level.TICK &block
+ $top_level.define_method(:tick) do |args|
+ args.outputs[:scene].w = 160
+ args.outputs[:scene].h = 90
+ args.outputs[:scene].background_color = [0, 0, 0, 0]
+ block.call args
+ args.outputs.sprites << { x: 0, y: 0, w: 1280, h: 720, path: :scene }
+ end
+
+ def $top_level.bg! *rgb
+ r,g,b = rgb
+ r ||= 255
+ g ||= r
+ b ||= g
+ $args.outputs.background_color = [r, g, b]
+ end
+
+ def $top_level.slds
+ $args.outputs[:scene].sprites
+ end
+
+ def $top_level.slds! *os
+ if (os.first.is_a? Numeric)
+ sld! *os
+ else
+ os.each { |o| sld! *o }
+ end
+ end
+
+ def $top_level.sld! *params
+ x, y, w, h, r, g, b, a = nil
+ if params.length == 2
+ x, y = params
+ elsif params.length == 3 && (params.last.is_a? Array)
+ x = params[0]
+ y = params[1]
+ r, g, b, a = params[2]
+ r ||= 255
+ g ||= r
+ b ||= g
+ a ||= 255
+ elsif params.length == 4
+ x, y, w, h = params
+ elsif params.length == 5 && (params.last.is_a? Array)
+ x = params[0]
+ y = params[1]
+ w = params[2]
+ h = params[3]
+ r,g,b,a = params[4]
+ r ||= 255
+ g ||= r
+ b ||= g
+ a ||= 255
+ elsif params.length >= 7
+ x, y, w, h, r, g, b = params
+ else
+ raise "I don't know how to render #{params} with reasonable defaults."
+ end
+
+ w ||= 1
+ h ||= 1
+ r ||= 255
+ g ||= 255
+ b ||= 255
+ a ||= 255
+
+ slds << { x: x, y: y,
+ w: w, h: h,
+ r: r, g: g, b: b, a: a,
+ path: :pixel }
+ end
+end
+
+=begin
+wht = [255] * 3
+red = [255, 0, 0]
+blu = [0, 130, 255]
+purp = [150, 80, 255]
+
+TICK {
+ bg! 0
+
+ slds << [0, 0, 3, 3, 0, 255, 0, 255]
+
+ sld! 10, 10
+ sld! 20, 20, 3, 2
+ sld! 30, 30, 2, 2, red
+ sld! 35, 35, blu
+
+ slds! 40, 40
+
+ slds! [50, 50],
+ [60, 60, purp],
+ [70, 70, 10, 10, wht],
+ [80, 80, 4, 4, 255, 0, 255]
+}
+=end