mirror of
https://github.com/TimeCrafters/timecrafters_configuration_tool_desktop.git
synced 2025-12-16 22:02:34 +00:00
Compare commits
21 Commits
v0.5.1
...
308575dc63
| Author | SHA1 | Date | |
|---|---|---|---|
| 308575dc63 | |||
| 94cd822b0c | |||
| c312f4839d | |||
| 3a8f4e5860 | |||
| 7e09031257 | |||
| 905ced174b | |||
| 510a24644b | |||
| 570d965669 | |||
| 60356fc7fa | |||
| 41f5710b4a | |||
| 1e21c64a18 | |||
| 451568003a | |||
| cce1c2c341 | |||
| d5cf1cb6a2 | |||
| a96cc7c604 | |||
| c2e527653d | |||
| 66b0eb3d1e | |||
| 655b418d70 | |||
| a8fc2dccde | |||
| 0d6fb8a657 | |||
| 15d8e2ff62 |
2
Gemfile
2
Gemfile
@@ -2,8 +2,6 @@ source "https://rubygems.org"
|
||||
|
||||
gem "cyberarm_engine"
|
||||
gem "gosu_notifications"
|
||||
gem "ffi"
|
||||
gem "clipboard"
|
||||
|
||||
group :packaging do
|
||||
gem "ocra"
|
||||
|
||||
41
README.md
41
README.md
@@ -1 +1,42 @@
|
||||
# TimeCrafters Configuration Tool for Desktop
|
||||
A desktop app for editing, either locally or remotely, JSON configuration files on the Robot Controller/Rev Control Hub.
|
||||
|
||||

|
||||
|
||||
## Features
|
||||
* TACNET - **T**imeCrafters **A**uxiliary **C**onfiguration **NET**work.
|
||||
* Enables syncing configurations between devices.
|
||||
|
||||
* Multiple Configurations
|
||||
* Create multiple configurations for specific robots/projects.
|
||||
|
||||
* Presets
|
||||
* Save Groups or Actions as Presets to quickly add pre-configurated Groups and Actions.
|
||||
|
||||
* Search
|
||||
* Search through the active configurations Groups, Actions, Variables and Presets.
|
||||
|
||||
* Built-in practice clock
|
||||
* Supports multiple screens or network remote control.
|
||||
* Supports official clock sounds (must be added manually.)
|
||||
* Built-in jukebox.
|
||||
|
||||
* Simulator
|
||||
* Create a simple 2D simulation of your robot's path.
|
||||
|
||||
* Field Planner
|
||||
* Estimate distances on the field using imperial or metric units.
|
||||
|
||||
## Usage
|
||||
* Download from [Releases](https://github.com/TimeCrafters/timecrafters_configuration_tool_desktop/releases/latest)
|
||||
|
||||
## Developing
|
||||
* Install [Ruby](https://ruby-lang.org)
|
||||
* Run `bundle install`
|
||||
* Run `bundle exec ruby timecrafters_configuration_tool.rb`
|
||||
|
||||
## Contributing
|
||||
* Clone this repo and create a new branch for your feature/patch.
|
||||
* Author your changes
|
||||
* Commit your changes and push to your fork
|
||||
* Open a pull request
|
||||
|
||||
@@ -42,13 +42,13 @@ module TAC
|
||||
end
|
||||
|
||||
def move_config(old_name, new_name)
|
||||
if not File.exists?("#{TAC::CONFIGS_PATH}/#{old_name}.json") or
|
||||
if not File.exist?("#{TAC::CONFIGS_PATH}/#{old_name}.json") or
|
||||
File.directory?("#{TAC::CONFIGS_PATH}/#{old_name}.json")
|
||||
# move_config: Can not move config file "#{old_name}" does not exist!
|
||||
return false
|
||||
end
|
||||
|
||||
if File.exists?("#{TAC::CONFIGS_PATH}/#{new_name}.json") &&
|
||||
if File.exist?("#{TAC::CONFIGS_PATH}/#{new_name}.json") &&
|
||||
!File.directory?("#{TAC::CONFIGS_PATH}/#{old_name}.json")
|
||||
# move_config: Config file "#{new_name}" already exist!
|
||||
return false
|
||||
@@ -61,7 +61,7 @@ module TAC
|
||||
end
|
||||
|
||||
def delete_config(config_name)
|
||||
FileUtils.rm("#{TAC::CONFIGS_PATH}/#{config_name}.json") if File.exists?("#{TAC::CONFIGS_PATH}/#{config_name}.json")
|
||||
FileUtils.rm("#{TAC::CONFIGS_PATH}/#{config_name}.json") if File.exist?("#{TAC::CONFIGS_PATH}/#{config_name}.json")
|
||||
end
|
||||
|
||||
|
||||
@@ -101,7 +101,7 @@ module TAC
|
||||
end
|
||||
|
||||
def refresh_tacnet_status
|
||||
$window.current_state.refresh_tacnet_status
|
||||
CyberarmEngine::Window.instance.current_state.refresh_tacnet_status
|
||||
end
|
||||
|
||||
|
||||
|
||||
@@ -5,51 +5,32 @@ module TAC
|
||||
background Gosu::Color.new(0xaa_000000)
|
||||
|
||||
@title = @options[:title] ? @options[:title] : "#{self.class}"
|
||||
@window_width, @window_height = window.width, window.height
|
||||
@previous_state = window.previous_state
|
||||
|
||||
@dialog_root = stack width: 0.25, border_thickness: 2, border_color: [TAC::Palette::TIMECRAFTERS_PRIMARY, TAC::Palette::TIMECRAFTERS_SECONDARY] do
|
||||
@dialog_root = stack(width: 0.25, h_align: :center, v_align: :center, border_thickness: 2, border_color: [TAC::Palette::TIMECRAFTERS_PRIMARY, TAC::Palette::TIMECRAFTERS_SECONDARY]) do
|
||||
# Title bar
|
||||
@titlebar = flow width: 1.0 do
|
||||
@titlebar = flow(width: 1.0, height: 36) do
|
||||
background [TAC::Palette::TIMECRAFTERS_PRIMARY, TAC::Palette::TIMECRAFTERS_SECONDARY]
|
||||
|
||||
# title
|
||||
flow width: 0.9 do
|
||||
label @title, text_size: THEME_SUBHEADING_TEXT_SIZE, width: 1.0, text_align: :center, text_border: true, text_border_color: 0xff_222222, text_border_size: 1
|
||||
end
|
||||
label @title, text_size: THEME_SUBHEADING_TEXT_SIZE, font: TAC::THEME_BOLD_FONT, fill: true, text_align: :center, text_border: true, text_border_color: 0xaa_222222, text_border_size: 1
|
||||
|
||||
# Buttons
|
||||
flow width: 0.0999 do
|
||||
button get_image("#{TAC::ROOT_PATH}/media/icons/cross.png"), image_width: 1.0, **THEME_DANGER_BUTTON do
|
||||
close
|
||||
end
|
||||
button get_image("#{TAC::ROOT_PATH}/media/icons/cross.png"), image_height: 1.0, **THEME_DANGER_BUTTON do
|
||||
close
|
||||
end
|
||||
end
|
||||
|
||||
# Dialog body
|
||||
@dialog_content = stack width: 1.0 do
|
||||
@dialog_content = stack(width: 1.0, scroll: true) do
|
||||
end
|
||||
end
|
||||
|
||||
@dialog_content.clear do
|
||||
build
|
||||
end
|
||||
|
||||
@root_container.recalculate
|
||||
@root_container.recalculate
|
||||
@root_container.recalculate
|
||||
|
||||
center_dialog
|
||||
end
|
||||
|
||||
def build
|
||||
end
|
||||
|
||||
def center_dialog
|
||||
@dialog_root.style.x = window.width / 2 - @dialog_root.width / 2
|
||||
@dialog_root.style.y = window.height / 2 - @dialog_root.height / 2
|
||||
end
|
||||
|
||||
def name_filter(text)
|
||||
text.match(/[A-Za-z0-9._\- ]/) ? text : ""
|
||||
end
|
||||
@@ -76,11 +57,12 @@ module TAC
|
||||
|
||||
def _deep_dive_interactive_elements(element, list)
|
||||
element.children.each do |child|
|
||||
if child.visible? && child.is_a?(CyberarmEngine::Element::EditLine) ||
|
||||
child.is_a?(CyberarmEngine::Element::EditBox) ||
|
||||
child.is_a?(CyberarmEngine::Element::CheckBox) ||
|
||||
child.is_a?(CyberarmEngine::Element::ToggleButton) ||
|
||||
child.is_a?(CyberarmEngine::Element::ListBox)
|
||||
if child.visible? && child.enabled? &&
|
||||
child.is_a?(CyberarmEngine::Element::EditLine) ||
|
||||
child.is_a?(CyberarmEngine::Element::EditBox) ||
|
||||
child.is_a?(CyberarmEngine::Element::CheckBox) ||
|
||||
child.is_a?(CyberarmEngine::Element::ToggleButton) ||
|
||||
child.is_a?(CyberarmEngine::Element::ListBox)
|
||||
|
||||
list << child
|
||||
elsif child.visible? && child.is_a?(CyberarmEngine::Element::Container)
|
||||
@@ -90,24 +72,12 @@ module TAC
|
||||
end
|
||||
|
||||
def draw
|
||||
@previous_state.draw
|
||||
previous_state&.draw
|
||||
Gosu.flush
|
||||
|
||||
super
|
||||
end
|
||||
|
||||
def update
|
||||
super
|
||||
|
||||
if window.width != @window_width or window.height != @window_height
|
||||
request_recalculate
|
||||
|
||||
@window_width, @window_height = window.width, window.height
|
||||
end
|
||||
|
||||
center_dialog
|
||||
end
|
||||
|
||||
def button_down(id)
|
||||
super
|
||||
|
||||
@@ -122,7 +92,7 @@ module TAC
|
||||
end
|
||||
|
||||
def close
|
||||
$window.pop_state
|
||||
pop_state
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -7,7 +7,7 @@ module TAC
|
||||
label "Name", width: 1.0, text_align: :center
|
||||
@name_error = label "Error", color: TAC::Palette::TACNET_CONNECTION_ERROR
|
||||
@name_error.hide
|
||||
@name = edit_line @options[:action] ? @options[:action].name : "", filter: method(:name_filter), width: 1.0, autofocus: true
|
||||
@name = edit_line @options[:action] ? @options[:action].name : "", filter: method(:name_filter), width: 1.0, autofocus: true, focus: true
|
||||
@name.subscribe(:changed) do |sender, value|
|
||||
valid?
|
||||
end
|
||||
|
||||
@@ -22,17 +22,17 @@ module TAC
|
||||
try_commit(true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def try_commit(force = false)
|
||||
if !@dangerous
|
||||
close
|
||||
def try_commit(force = false)
|
||||
if !@dangerous
|
||||
close
|
||||
|
||||
@options[:callback_method].call
|
||||
elsif @dangerous && force
|
||||
close
|
||||
@options[:callback_method].call
|
||||
elsif @dangerous && force
|
||||
close
|
||||
|
||||
@options[:callback_method].call
|
||||
end
|
||||
@options[:callback_method].call
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -8,7 +8,7 @@ module TAC
|
||||
label "Name", width: 1.0, text_align: :center
|
||||
@name_error = label "", color: TAC::Palette::TACNET_CONNECTION_ERROR
|
||||
@name_error.hide
|
||||
@name = edit_line @options[:renaming] ? @options[:renaming].name : "", filter: method(:name_filter), width: 1.0, autofocus: true
|
||||
@name = edit_line @options[:renaming] ? @options[:renaming].name : "", filter: method(:name_filter), width: 1.0, autofocus: true, focus: true
|
||||
|
||||
@name.subscribe(:changed) do |sender, value|
|
||||
valid?
|
||||
|
||||
@@ -3,14 +3,14 @@ module TAC
|
||||
class TACNETStatusDialog < Dialog
|
||||
def build
|
||||
background Gosu::Color::GRAY
|
||||
@message_label = label $window.backend.tacnet.full_status
|
||||
@message_label = label CyberarmEngine::Window.instance.backend.tacnet.full_status
|
||||
|
||||
button "Close", width: 1.0, margin_top: THEME_DIALOG_BUTTON_PADDING do
|
||||
try_commit
|
||||
end
|
||||
|
||||
@timer = CyberarmEngine::Timer.new(1000.0) do
|
||||
@message_label.value = $window.backend.tacnet.full_status
|
||||
@message_label.value = CyberarmEngine::Window.instance.backend.tacnet.full_status
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ module TAC
|
||||
label "Name", width: 1.0, text_align: :center
|
||||
@name_error = label "Error", color: TAC::Palette::TACNET_CONNECTION_ERROR
|
||||
@name_error.hide
|
||||
@name = edit_line @options[:variable] ? @options[:variable].name : "", filter: method(:name_filter), width: 1.0, autofocus: true
|
||||
@name = edit_line @options[:variable] ? @options[:variable].name : "", filter: method(:name_filter), width: 1.0, autofocus: true, focus: true
|
||||
@name.subscribe(:changed) do |sender, value|
|
||||
valid?
|
||||
end
|
||||
@@ -79,11 +79,22 @@ module TAC
|
||||
|
||||
def valid?
|
||||
valid = true
|
||||
name = @name.value.strip
|
||||
|
||||
if @name.value.strip.empty?
|
||||
if name.empty?
|
||||
@name_error.value = "Error: Name cannot be blank or only whitespace."
|
||||
@name_error.show
|
||||
valid = false
|
||||
|
||||
### Don't error if renaming variable to itself
|
||||
elsif @options[:variable] && @options[:variable].name == name
|
||||
@name_error.value = ""
|
||||
@name_error.hide
|
||||
|
||||
elsif @options[:list].find { |variable| variable.name == name }
|
||||
@name_error.value = "Error: Name is not unique!"
|
||||
@name_error.show
|
||||
valid = false
|
||||
end
|
||||
|
||||
if not @type
|
||||
|
||||
@@ -8,7 +8,7 @@ module TAC
|
||||
|
||||
def initialize
|
||||
@title = CyberarmEngine::Text.new("FIRST TECH CHALLENGE", size: TITLE_SIZE, text_shadow: true, y: 10, color: Gosu::Color::GRAY)
|
||||
@title.x = $window.width / 2 - @title.width / 2
|
||||
@title.x = CyberarmEngine::Window.instance.width / 2 - @title.width / 2
|
||||
|
||||
@text = CyberarmEngine::Text.new(":1234567890", size: CLOCK_SIZE, text_border: true, border_size: 2, border_color: Gosu::Color::GRAY)
|
||||
@text.width # trigger font-eager loading
|
||||
@@ -28,7 +28,7 @@ module TAC
|
||||
end
|
||||
|
||||
def update
|
||||
@title.x = $window.width / 2 - @title.width / 2
|
||||
@title.x = CyberarmEngine::Window.instance.width / 2 - @title.width / 2
|
||||
|
||||
if @controller
|
||||
@text.color = @controller.display_color
|
||||
@@ -38,8 +38,8 @@ module TAC
|
||||
@text.text = "0:00"
|
||||
end
|
||||
|
||||
@text.x = $window.width / 2 - @text.textobject.text_width("0:00") / 2
|
||||
@text.y = $window.height / 2 - @text.height / 2
|
||||
@text.x = CyberarmEngine::Window.instance.width / 2 - @text.textobject.text_width("0:00") / 2
|
||||
@text.y = CyberarmEngine::Window.instance.height / 2 - @text.height / 2
|
||||
|
||||
@controller&.update
|
||||
end
|
||||
|
||||
@@ -20,7 +20,7 @@ module TAC
|
||||
end
|
||||
|
||||
def start_clock(mode)
|
||||
return if @clock.active? || $window.current_state.is_a?(Randomizer)
|
||||
return if @clock.active? || CyberarmEngine::Window.instance.current_state.is_a?(Randomizer)
|
||||
|
||||
@clock.controller = case mode
|
||||
when :full_match
|
||||
@@ -45,7 +45,7 @@ module TAC
|
||||
|
||||
def set_clock_title(string)
|
||||
@clock.title.text = string.to_s
|
||||
@clock.title.x = $window.width / 2 - @clock.title.width / 2
|
||||
@clock.title.x = CyberarmEngine::Window.instance.width / 2 - @clock.title.width / 2
|
||||
end
|
||||
|
||||
def get_clock_title(string)
|
||||
|
||||
@@ -52,7 +52,7 @@ module TAC
|
||||
return minutes + seconds
|
||||
end
|
||||
|
||||
def play_sound(sound)
|
||||
def play_sound(sound)
|
||||
path = nil
|
||||
case sound
|
||||
when :autonomous_countdown
|
||||
|
||||
@@ -225,7 +225,7 @@ module TAC
|
||||
def handle_shutdown(packet)
|
||||
unless @host_is_a_connection
|
||||
# RemoteControl.server.close
|
||||
# $window.close
|
||||
# CyberarmEngine::Window.instance.close
|
||||
Gosu::Song.current_song&.stop
|
||||
exit
|
||||
end
|
||||
|
||||
@@ -18,7 +18,7 @@ module TAC
|
||||
end
|
||||
|
||||
def update
|
||||
@particles.each { |part| part.update($window.dt) }
|
||||
@particles.each { |part| part.update(CyberarmEngine::Window.instance.dt) }
|
||||
@particles.delete_if { |part| part.die? }
|
||||
|
||||
spawn_particles
|
||||
@@ -27,28 +27,28 @@ module TAC
|
||||
def spawn_particles
|
||||
# !clock_active? &&
|
||||
if @particles.count < @max_particles && Gosu.milliseconds - @last_spawned >= @interval
|
||||
screen_midpoint = CyberarmEngine::Vector.new($window.width / 2, $window.height / 2)
|
||||
screen_midpoint = CyberarmEngine::Vector.new(CyberarmEngine::Window.instance.width / 2, CyberarmEngine::Window.instance.height / 2)
|
||||
scale = rand(0.25..1.0)
|
||||
image_name = @image_options.sample
|
||||
|
||||
return unless image_name
|
||||
|
||||
image = $window.current_state.get_image(image_name)
|
||||
image = CyberarmEngine::Window.instance.current_state.get_image(image_name)
|
||||
position = CyberarmEngine::Vector.new(0, 0)
|
||||
|
||||
r = rand
|
||||
if r < 0.25 # LEFT
|
||||
position.x = -image.width * scale
|
||||
position.y = rand(0..($window.height - image.height * scale))
|
||||
position.y = rand(0..(CyberarmEngine::Window.instance.height - image.height * scale))
|
||||
elsif r < 0.5 # RIGHT
|
||||
position.x = $window.width + (image.width * scale)
|
||||
position.y = rand(0..($window.height - image.height * scale))
|
||||
position.x = CyberarmEngine::Window.instance.width + (image.width * scale)
|
||||
position.y = rand(0..(CyberarmEngine::Window.instance.height - image.height * scale))
|
||||
elsif r < 0.75 # TOP
|
||||
position.x = rand(0..($window.width - image.width * scale))
|
||||
position.x = rand(0..(CyberarmEngine::Window.instance.width - image.width * scale))
|
||||
position.y = -image.height * scale
|
||||
else #BOTTOM
|
||||
position.x = rand(0..($window.width - image.width * scale))
|
||||
position.y = $window.height + image.height * scale
|
||||
position.x = rand(0..(CyberarmEngine::Window.instance.width - image.width * scale))
|
||||
position.y = CyberarmEngine::Window.instance.height + image.height * scale
|
||||
end
|
||||
|
||||
position.x ||= 0
|
||||
@@ -71,6 +71,10 @@ module TAC
|
||||
end
|
||||
end
|
||||
|
||||
def particle_count
|
||||
@particles.size
|
||||
end
|
||||
|
||||
def clock_active!
|
||||
@clock_active = true
|
||||
@particles.each(&:clock_active!)
|
||||
|
||||
@@ -23,19 +23,27 @@ module TAC
|
||||
when 2, 5
|
||||
#Blue and Red: Center
|
||||
|
||||
@ducks << Ducky.new(window: window, alliance: :blue, slot: 2, speed: 512, die_size: @size)
|
||||
@ducks << Ducky.new(window: window, alliance: :red, slot: 2, speed: 512, die_size: @size)
|
||||
@ducks << Ducky.new(window: window, alliance: :blue, slot: 1, speed: 512, die_size: @size)
|
||||
@ducks << Ducky.new(window: window, alliance: :blue, slot: 3, speed: 512, die_size: @size)
|
||||
|
||||
@ducks << Ducky.new(window: window, alliance: :red, slot: 3, speed: 512, die_size: @size)
|
||||
@ducks << Ducky.new(window: window, alliance: :red, slot: 1, speed: 512, die_size: @size)
|
||||
when 3, 6
|
||||
# Blue: Left
|
||||
# Red: Right
|
||||
|
||||
@ducks << Ducky.new(window: window, alliance: :blue, slot: 1, speed: 512, die_size: @size)
|
||||
@ducks << Ducky.new(window: window, alliance: :blue, slot: 2, speed: 512, die_size: @size)
|
||||
@ducks << Ducky.new(window: window, alliance: :blue, slot: 3, speed: 512, die_size: @size)
|
||||
|
||||
@ducks << Ducky.new(window: window, alliance: :red, slot: 3, speed: 512, die_size: @size)
|
||||
@ducks << Ducky.new(window: window, alliance: :red, slot: 2, speed: 512, die_size: @size)
|
||||
@ducks << Ducky.new(window: window, alliance: :red, slot: 1, speed: 512, die_size: @size)
|
||||
end
|
||||
end
|
||||
|
||||
def draw
|
||||
window.previous_state.draw
|
||||
previous_state.draw
|
||||
|
||||
Gosu.flush
|
||||
|
||||
@@ -56,7 +64,7 @@ module TAC
|
||||
end
|
||||
|
||||
def update
|
||||
window.previous_state&.update_non_gui
|
||||
previous_state&.update_non_gui
|
||||
|
||||
@ducks.each { |o| o.update(@size) }
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ module TAC
|
||||
@clock = Clock.new
|
||||
@clock.controller = nil
|
||||
@last_clock_display_value = @clock.value
|
||||
@last_clock_title_value = @clock.title.text
|
||||
|
||||
@particle_emitters = [
|
||||
PracticeGameClock::ParticleEmitter.new
|
||||
@@ -72,17 +73,17 @@ module TAC
|
||||
stack width: 0.4, padding_left: 50 do
|
||||
background @menu_background
|
||||
|
||||
flow do
|
||||
flow(width: 1.0) do
|
||||
label "♫ Now playing:"
|
||||
@current_song_label = label "♫ ♫ ♫"
|
||||
end
|
||||
|
||||
flow do
|
||||
flow(width: 1.0) do
|
||||
label "Volume:"
|
||||
@current_volume_label = label "100%"
|
||||
end
|
||||
|
||||
flow do
|
||||
flow(width: 1.0) do
|
||||
button get_image("#{ROOT_PATH}/media/icons/previous.png") do
|
||||
@jukebox.previous_track
|
||||
end
|
||||
@@ -137,7 +138,7 @@ module TAC
|
||||
end
|
||||
end
|
||||
|
||||
stack width: 1.0 do
|
||||
stack(width: 1.0) do
|
||||
button "Randomizer", width: 1.0, **TAC::THEME_DANGER_BUTTON do
|
||||
unless @clock.active?
|
||||
push_state(Randomizer)
|
||||
@@ -195,11 +196,19 @@ module TAC
|
||||
if @clock.value != @last_clock_display_value
|
||||
@last_clock_display_value = @clock.value
|
||||
|
||||
request_repaint
|
||||
|
||||
if @remote_control_mode && @server.active_client
|
||||
@server.active_client.puts(ClockNet::PacketHandler.packet_clock_time(@last_clock_display_value))
|
||||
end
|
||||
end
|
||||
|
||||
if @clock.title.text != @last_clock_title_value
|
||||
@last_clock_title_value = @clock.title.text
|
||||
|
||||
request_repaint
|
||||
end
|
||||
|
||||
if @last_track_name != @jukebox.current_track
|
||||
track_changed(@jukebox.current_track)
|
||||
end
|
||||
@@ -213,6 +222,14 @@ module TAC
|
||||
@last_clock_state = @clock.active?
|
||||
end
|
||||
|
||||
def request_repaint
|
||||
if @particle_emitters && @particle_emitters.map(&:particle_count).sum.positive?
|
||||
true
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
def update_non_gui
|
||||
if @remote_control_mode
|
||||
while (o = RemoteControl.server.proxy_object.queue.shift)
|
||||
|
||||
@@ -13,15 +13,27 @@ module TAC
|
||||
populate_configs
|
||||
})
|
||||
end
|
||||
|
||||
button "Open Folder", tip: "Open folder containing configurations", height: 1.0 do
|
||||
if RUBY_PLATFORM =~ /mingw/
|
||||
system("start \"#{TAC::CONFIGS_PATH}\"")
|
||||
elsif RUBY_PLATFORM =~ /darwin/
|
||||
system("open \"#{TAC::CONFIGS_PATH}\"")
|
||||
else
|
||||
system("xdg-open \"#{TAC::CONFIGS_PATH}\"")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
status_bar.clear do
|
||||
label "Current Configuration: "
|
||||
@config_label = label window.backend.settings.config
|
||||
flow(width: 1.0, max_width: 720, h_align: :center) do
|
||||
label "Current Configuration: "
|
||||
@config_label = label window.backend.settings.config
|
||||
end
|
||||
end
|
||||
|
||||
body.clear do
|
||||
@configs_list = stack width: 1.0, height: 1.0, scroll: true do
|
||||
@configs_list = stack width: 1.0, height: 1.0, margin_top: 36, max_width: 720, h_align: :center, scroll: true do
|
||||
end
|
||||
end
|
||||
|
||||
@@ -34,12 +46,13 @@ module TAC
|
||||
|
||||
@configs_list.clear do
|
||||
@config_files.each_with_index do |config_file, i|
|
||||
flow width: 1.0, **THEME_ITEM_CONTAINER_PADDING do
|
||||
background i.even? ? THEME_EVEN_COLOR : THEME_ODD_COLOR
|
||||
|
||||
flow width: 1.0, height: 36, **THEME_ITEM_CONTAINER_PADDING do
|
||||
name = File.basename(config_file, ".json")
|
||||
|
||||
button "#{name}", width: 0.94 do
|
||||
background i.even? ? THEME_EVEN_COLOR : THEME_ODD_COLOR unless name == window.backend.settings.config
|
||||
background THEME_HIGHLIGHTED_COLOR if name == window.backend.settings.config
|
||||
|
||||
button "#{name}", fill: true, text_size: THEME_ICON_SIZE - 3 do
|
||||
change_config(name)
|
||||
|
||||
if window.backend.tacnet.connected?
|
||||
@@ -92,6 +105,8 @@ module TAC
|
||||
window.backend.load_config(name)
|
||||
|
||||
@config_label.value = name.to_s
|
||||
|
||||
populate_configs
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -7,18 +7,20 @@ module TAC
|
||||
header_bar("Drive Team Rotation Generator")
|
||||
|
||||
@roster ||= [
|
||||
"Alexander",
|
||||
"Aubrey",
|
||||
"Cayden",
|
||||
"Dan",
|
||||
"Gabe",
|
||||
"Spencer",
|
||||
"Olivia"
|
||||
"Sodi",
|
||||
"Trent"
|
||||
]
|
||||
|
||||
@roles ||= [
|
||||
"Coach",
|
||||
"Driver A",
|
||||
"Driver B"
|
||||
"Driver B",
|
||||
"Human"
|
||||
]
|
||||
|
||||
menu_bar.clear do
|
||||
@@ -30,19 +32,19 @@ module TAC
|
||||
end
|
||||
end
|
||||
|
||||
button get_image("#{TAC::ROOT_PATH}/media/icons/target.png"), margin_right: 10, image_height: 1.0, tip: "Generate rotation" do
|
||||
button "Generate", margin_right: 10, height: 1.0, tip: "Generate rotation" do
|
||||
populate_rotation
|
||||
end
|
||||
end
|
||||
|
||||
body.clear do
|
||||
flow(margin_left: 20, width: 1.0, height: 1.0) do
|
||||
stack(width: 0.25) do
|
||||
stack(width: 0.25, height: 1.0) do
|
||||
title "Roles", width: 1.0, margin_bottom: 4, text_align: :center
|
||||
|
||||
flow(width: 1.0, margin_bottom: 20) do
|
||||
@role_name = edit_line "", placeholder: "Add role", width: 0.9
|
||||
button get_image("#{TAC::ROOT_PATH}/media/icons/plus.png"), image_width: 0.1, tip: "Add role" do
|
||||
flow(width: 1.0, height: 32, margin_bottom: 20) do
|
||||
@role_name = edit_line "", placeholder: "Add role", fill: true, height: 1.0
|
||||
button get_image("#{TAC::ROOT_PATH}/media/icons/plus.png"), image_height: 1.0, tip: "Add role" do
|
||||
if @role_name.value.strip.length.positive?
|
||||
@roles.push(@role_name.value.strip)
|
||||
@role_name.value = ""
|
||||
@@ -52,16 +54,16 @@ module TAC
|
||||
end
|
||||
end
|
||||
|
||||
@roles_container = stack(width: 1.0, height: 0.835, scroll: true) do
|
||||
@roles_container = stack(width: 1.0, fill: true, scroll: true) do
|
||||
end
|
||||
end
|
||||
|
||||
stack(margin_left: 20, width: 0.25, height: 1.0) do
|
||||
title "Roster", width: 1.0, margin_bottom: 4, text_align: :center
|
||||
|
||||
flow(width: 1.0, margin_bottom: 20) do
|
||||
@roster_name = edit_line "", placeholder: "Add name", width: 0.9
|
||||
button get_image("#{TAC::ROOT_PATH}/media/icons/plus.png"), image_width: 0.1, tip: "Add name" do
|
||||
flow(width: 1.0, height: 32, margin_bottom: 20) do
|
||||
@roster_name = edit_line "", placeholder: "Add name", height: 1.0, fill: true
|
||||
button get_image("#{TAC::ROOT_PATH}/media/icons/plus.png"), image_height: 1.0, tip: "Add name" do
|
||||
if @roster_name.value.strip.length.positive?
|
||||
@roster.push(@roster_name.value.strip)
|
||||
@roster_name.value = ""
|
||||
@@ -71,14 +73,14 @@ module TAC
|
||||
end
|
||||
end
|
||||
|
||||
@roster_container = stack(width: 1.0, height: 0.835, scroll: true) do
|
||||
@roster_container = stack(width: 1.0, fill: true, scroll: true) do
|
||||
end
|
||||
end
|
||||
|
||||
stack(margin_left: 20, margin_right: 20, width: 0.5, height: 1.0) do
|
||||
stack(margin_left: 20, margin_right: 20, fill: true, height: 1.0) do
|
||||
title "Rotation", width: 1.0, margin_bottom: 4, text_align: :center
|
||||
|
||||
@rotation_container = stack(width: 1.0, height: 0.835, scroll: true) do
|
||||
@rotation_container = stack(width: 1.0, fill: true, scroll: true) do
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -92,11 +94,11 @@ module TAC
|
||||
def populate_roles
|
||||
@roles_container.clear do
|
||||
@roles.each_with_index do |name, i|
|
||||
flow(width: 1.0, padding: 2) do
|
||||
flow(width: 1.0, height: 32, padding: 2) do
|
||||
background i.even? ? 0xff_007000 : 0xff_006000
|
||||
|
||||
tagline name, width: 0.9
|
||||
button get_image("#{TAC::ROOT_PATH}/media/icons/trashcan.png"), image_width: 0.1, tip: "Remove role", **THEME_DANGER_BUTTON do
|
||||
tagline name, fill: true
|
||||
button get_image("#{TAC::ROOT_PATH}/media/icons/trashcan.png"), image_height: 1.0, tip: "Remove role", **THEME_DANGER_BUTTON do
|
||||
@roles.delete(name)
|
||||
populate_roles
|
||||
end
|
||||
@@ -108,11 +110,11 @@ module TAC
|
||||
def populate_roster
|
||||
@roster_container.clear do
|
||||
@roster.each_with_index do |name, i|
|
||||
flow(width: 1.0, padding: 2) do
|
||||
flow(width: 1.0, height: 32, padding: 2) do
|
||||
background i.even? ? 0xff_007000 : 0xff_006000
|
||||
|
||||
tagline name, width: 0.9
|
||||
button get_image("#{TAC::ROOT_PATH}/media/icons/trashcan.png"), image_width: 0.1, tip: "Remove name", **THEME_DANGER_BUTTON do
|
||||
tagline name, fill: true
|
||||
button get_image("#{TAC::ROOT_PATH}/media/icons/trashcan.png"), image_height: 1.0, tip: "Remove name", **THEME_DANGER_BUTTON do
|
||||
@roster.delete(name)
|
||||
populate_roster
|
||||
end
|
||||
@@ -125,13 +127,11 @@ module TAC
|
||||
@rotation = Generator.new(roster: @roster, team_size: @roles.count)
|
||||
|
||||
@rotation_container.clear do
|
||||
fraction = (1.0 / @rotation.team_size) - 0.02
|
||||
|
||||
flow(width: 1.0, padding: 2) do
|
||||
flow(width: 1.0, height: 32, padding: 2) do
|
||||
background Gosu::Color::BLACK
|
||||
|
||||
@roles.each do |role|
|
||||
tagline "<b>#{role}</b>", width: fraction
|
||||
tagline "<b>#{role}</b>", fill: true
|
||||
end
|
||||
end
|
||||
|
||||
@@ -139,11 +139,11 @@ module TAC
|
||||
teams = @rotation.teams.shuffle if @shuffle_teams&.value
|
||||
|
||||
teams.each_with_index do |team, i|
|
||||
flow(width: 1.0, padding: 2) do
|
||||
flow(width: 1.0, height: 32, padding: 2) do
|
||||
background i.even? ? 0xff_007000 : 0xff_006000
|
||||
|
||||
team.each do |player|
|
||||
tagline player, width: fraction
|
||||
tagline player, fill: true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -30,9 +30,9 @@ module TAC
|
||||
|
||||
body.clear do
|
||||
flow(width: 1.0, height: 1.0) do
|
||||
stack width: 0.33333, height: 1.0, border_thickness_right: 1, border_color: [0, Gosu::Color::BLACK, 0, 0] do
|
||||
@groups_menu = flow(width: 1.0) do
|
||||
label "Groups", text_size: THEME_SUBHEADING_TEXT_SIZE
|
||||
stack fill: true, height: 1.0, padding_left: 2, padding_right: 2, border_thickness_right: 1, border_color: Gosu::Color::BLACK do
|
||||
@groups_menu = flow(width: 1.0, height: 36) do
|
||||
label "Groups", text_size: THEME_SUBHEADING_TEXT_SIZE, fill: true, text_align: :center
|
||||
|
||||
button get_image("#{TAC::ROOT_PATH}/media/icons/plus.png"), image_width: THEME_ICON_SIZE, tip: "Add group" do
|
||||
push_state(TAC::Dialog::NamePromptDialog, title: "Create Group", list: window.backend.config.groups, callback_method: method(:create_group))
|
||||
@@ -42,7 +42,8 @@ module TAC
|
||||
if @active_group
|
||||
push_state(Dialog::NamePromptDialog, title: "Clone Group", renaming: @active_group, accept_label: "Clone", list: window.backend.config.groups, callback_method: proc { |group, name|
|
||||
clone = TAC::Config::Group.from_json( JSON.parse( @active_group.to_json, symbolize_names: true ))
|
||||
clone.name = "#{name}"
|
||||
clone.name = name.to_s
|
||||
|
||||
window.backend.config.groups << clone
|
||||
window.backend.config_changed!
|
||||
|
||||
@@ -57,7 +58,8 @@ module TAC
|
||||
if @active_group
|
||||
push_state(Dialog::NamePromptDialog, title: "Save Group Preset", renaming: @active_group, accept_label: "Save", list: window.backend.config.presets.groups, callback_method: proc { |group, name|
|
||||
clone = TAC::Config::Group.from_json( JSON.parse( @active_group.to_json, symbolize_names: true ))
|
||||
clone.name = "#{name}"
|
||||
clone.name = name.to_s
|
||||
|
||||
window.backend.config.presets.groups << clone
|
||||
window.backend.config.presets.groups.sort_by! { |g| g.name.downcase }
|
||||
window.backend.config_changed!
|
||||
@@ -73,7 +75,8 @@ module TAC
|
||||
push_state(Dialog::PickPresetDialog, title: "Pick Group Preset", limit: :groups, callback_method: proc { |preset|
|
||||
push_state(Dialog::NamePromptDialog, title: "Name Group", renaming: preset, accept_label: "Add", list: window.backend.config.groups, callback_method: proc { |group, name|
|
||||
clone = TAC::Config::Group.from_json( JSON.parse( group.to_json, symbolize_names: true ))
|
||||
clone.name = "#{name}"
|
||||
clone.name = name.to_s
|
||||
|
||||
window.backend.config.groups << clone
|
||||
window.backend.config.groups.sort_by! { |g| g.name.downcase }
|
||||
window.backend.config_changed!
|
||||
@@ -84,13 +87,13 @@ module TAC
|
||||
end
|
||||
end
|
||||
|
||||
@groups_list = stack width: 1.0, scroll: true do
|
||||
@groups_list = stack width: 1.0, fill: true, scroll: true do
|
||||
end
|
||||
end
|
||||
|
||||
stack width: 0.33333, height: 1.0, border_thickness_right: 1, border_color: [0, Gosu::Color::BLACK, 0, 0] do
|
||||
@actions_menu = flow(width: 1.0) do
|
||||
label "Actions", text_size: THEME_SUBHEADING_TEXT_SIZE
|
||||
stack fill: true, height: 1.0, padding_left: 2, padding_right: 2, border_thickness_right: 1, border_color: Gosu::Color::BLACK do
|
||||
@actions_menu = flow(width: 1.0, height: 36) do
|
||||
label "Actions", text_size: THEME_SUBHEADING_TEXT_SIZE, fill: true, text_align: :center
|
||||
|
||||
button get_image("#{TAC::ROOT_PATH}/media/icons/plus.png"), image_width: THEME_ICON_SIZE, tip: "Add action" do
|
||||
if @active_group
|
||||
@@ -106,6 +109,7 @@ module TAC
|
||||
clone = TAC::Config::Action.from_json( JSON.parse( @active_action.to_json, symbolize_names: true ))
|
||||
clone.name = name
|
||||
clone.comment = comment
|
||||
|
||||
@active_group.actions << clone
|
||||
window.backend.config_changed!
|
||||
|
||||
@@ -121,6 +125,7 @@ module TAC
|
||||
push_state(Dialog::NamePromptDialog, title: "Save Action Preset", renaming: @active_action, accept_label: "Save", list: window.backend.config.presets.actions, callback_method: proc { |action, name|
|
||||
clone = TAC::Config::Action.from_json( JSON.parse( @active_action.to_json, symbolize_names: true ))
|
||||
clone.name = "#{name}"
|
||||
|
||||
window.backend.config.presets.actions << clone
|
||||
window.backend.config.presets.actions.sort_by! { |a| a.name.downcase }
|
||||
window.backend.config_changed!
|
||||
@@ -135,9 +140,12 @@ module TAC
|
||||
button get_image("#{TAC::ROOT_PATH}/media/icons/import.png"), image_width: THEME_ICON_SIZE, tip: "Import action from preset" do
|
||||
if @active_group
|
||||
push_state(Dialog::PickPresetDialog, title: "Pick Action Preset", limit: :actions, callback_method: proc { |preset|
|
||||
push_state(Dialog::ActionDialog, title: "Name Action", action: preset, accept_label: "Add", list: @active_group.actions, callback_method: proc { |action, name|
|
||||
push_state(Dialog::ActionDialog, title: "Name Action", action: preset, accept_label: "Add", list: @active_group.actions, callback_method: proc { |action, name, comment|
|
||||
clone = TAC::Config::Action.from_json( JSON.parse( action.to_json, symbolize_names: true ))
|
||||
clone.name = "#{name}"
|
||||
clone.name = name.to_s
|
||||
clone.comment = comment.to_s
|
||||
clone.enabled = true
|
||||
|
||||
@active_group.actions << clone
|
||||
@active_group.actions.sort_by! { |a| a.name.downcase }
|
||||
window.backend.config_changed!
|
||||
@@ -151,33 +159,37 @@ module TAC
|
||||
end
|
||||
end
|
||||
|
||||
@actions_list = stack width: 1.0, scroll: true do
|
||||
@actions_list = stack width: 1.0, fill: true, scroll: true do
|
||||
end
|
||||
end
|
||||
|
||||
stack width: 0.331, height: 1.0 do
|
||||
@variables_menu = flow(width: 1.0) do
|
||||
label "Variables", text_size: THEME_SUBHEADING_TEXT_SIZE
|
||||
stack fill: true, height: 1.0, padding_left: 2, padding_right: 2 do
|
||||
@variables_menu = flow(width: 1.0, height: 36) do
|
||||
label "Variables", text_size: THEME_SUBHEADING_TEXT_SIZE, fill: true, text_align: :center
|
||||
button get_image("#{TAC::ROOT_PATH}/media/icons/plus.png"), image_width: THEME_ICON_SIZE, tip: "Add variable" do
|
||||
if @active_action
|
||||
push_state(TAC::Dialog::VariableDialog, title: "Create Variable", callback_method: method(:create_variable))
|
||||
push_state(TAC::Dialog::VariableDialog, title: "Create Variable", list: @active_action.variables, callback_method: method(:create_variable))
|
||||
else
|
||||
push_state(TAC::Dialog::AlertDialog, title: "Error", message: "Unable to create variable, no action selected.")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@variables_list = stack width: 1.0, scroll: true do
|
||||
@variables_list = stack width: 1.0, fill: true, scroll: true do
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
populate_groups_list
|
||||
populated_groups_list = false
|
||||
|
||||
if @options[:group_is_preset]
|
||||
populated_groups_list = true
|
||||
|
||||
@active_group = @options[:group]
|
||||
@active_group_label.value = @active_group.name
|
||||
|
||||
populate_groups_list
|
||||
populate_actions_list(@active_group)
|
||||
|
||||
@groups_menu.hide
|
||||
@@ -193,15 +205,20 @@ module TAC
|
||||
|
||||
else
|
||||
if @options[:group]
|
||||
populated_groups_list = true
|
||||
|
||||
@active_group = @options[:group]
|
||||
@active_group_label.value = @active_group.name
|
||||
|
||||
populate_actions_list(@active_group)
|
||||
populate_groups_list
|
||||
populate_actions_list(@active_group) unless @options[:action]
|
||||
|
||||
if @options[:action]
|
||||
@active_action = @options[:action]
|
||||
@active_action_label.value = @active_action.name
|
||||
|
||||
populate_actions_list(@active_group)
|
||||
|
||||
populate_variables_list(@active_action)
|
||||
|
||||
if @options[:variable]
|
||||
@@ -211,15 +228,7 @@ module TAC
|
||||
end
|
||||
end
|
||||
|
||||
body.root.subscribe(:window_size_changed) do
|
||||
set_list_heights
|
||||
end
|
||||
end
|
||||
|
||||
def set_list_heights
|
||||
@groups_list.style.height = body.height - @groups_menu.height
|
||||
@actions_list.style.height = body.height - @actions_menu.height
|
||||
@variables_list.style.height = body.height - @variables_menu.height
|
||||
populate_groups_list unless populated_groups_list
|
||||
end
|
||||
|
||||
def create_group(name)
|
||||
@@ -244,8 +253,10 @@ module TAC
|
||||
window.backend.config_changed!
|
||||
|
||||
@active_group = nil
|
||||
@active_group_container = nil
|
||||
@active_group_label.value = ""
|
||||
@active_action = nil
|
||||
@active_active_container = nil
|
||||
@active_action_label.value = ""
|
||||
@actions_list.clear
|
||||
@variables_list.clear
|
||||
@@ -264,6 +275,7 @@ module TAC
|
||||
def update_action(action, name, comment)
|
||||
action.name = name
|
||||
action.comment = comment
|
||||
@active_group.actions.sort_by! { |a| a.name.downcase }
|
||||
window.backend.config_changed!
|
||||
|
||||
populate_actions_list(@active_group)
|
||||
@@ -320,13 +332,21 @@ module TAC
|
||||
|
||||
@groups_list.clear do
|
||||
groups.each_with_index do |group, i|
|
||||
flow width: 1.0, **THEME_ITEM_CONTAINER_PADDING do
|
||||
background i.even? ? THEME_EVEN_COLOR : THEME_ODD_COLOR
|
||||
flow width: 1.0, height: 36, **THEME_ITEM_CONTAINER_PADDING do |container|
|
||||
background group == @active_group ? THEME_HIGHLIGHTED_COLOR : (i.even? ? THEME_EVEN_COLOR : THEME_ODD_COLOR)
|
||||
@active_group_container = container if group == @active_group
|
||||
|
||||
button group.name, fill: true, text_size: THEME_ICON_SIZE - 3 do
|
||||
if (old_i = groups.index(@active_group))
|
||||
@active_group_container.style.default[:background] = old_i.even? ? THEME_EVEN_COLOR : THEME_ODD_COLOR
|
||||
end
|
||||
|
||||
button group.name, width: 0.8 do
|
||||
@active_group = group
|
||||
@active_group_container = container
|
||||
@active_group_container.style.default[:background] = THEME_HIGHLIGHTED_COLOR
|
||||
@active_group_label.value = group.name
|
||||
@active_action = nil
|
||||
@active_action_container = nil
|
||||
@active_action_label.value = ""
|
||||
|
||||
populate_actions_list(group)
|
||||
@@ -342,8 +362,6 @@ module TAC
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
set_list_heights
|
||||
end
|
||||
|
||||
def populate_actions_list(group)
|
||||
@@ -353,12 +371,19 @@ module TAC
|
||||
|
||||
@actions_list.clear do
|
||||
actions.each_with_index do |action, i|
|
||||
stack width: 1.0, **THEME_ITEM_CONTAINER_PADDING do
|
||||
background i.even? ? THEME_EVEN_COLOR : THEME_ODD_COLOR
|
||||
stack width: 1.0, height: action.comment.empty? ? 36 : 72, **THEME_ITEM_CONTAINER_PADDING do |container|
|
||||
background action == @active_action ? THEME_HIGHLIGHTED_COLOR : (i.even? ? THEME_EVEN_COLOR : THEME_ODD_COLOR)
|
||||
@active_action_container = container if action == @active_action
|
||||
|
||||
flow width: 1.0, height: 36 do
|
||||
button action.name, fill: true, text_size: THEME_ICON_SIZE - 3 do
|
||||
if (old_i = actions.index(@active_action))
|
||||
@active_action_container.style.default[:background] = old_i.even? ? THEME_EVEN_COLOR : THEME_ODD_COLOR
|
||||
end
|
||||
|
||||
flow width: 1.0 do
|
||||
button action.name, width: 0.72 do
|
||||
@active_action = action
|
||||
@active_action_container = container
|
||||
@active_action_container.style.default[:background] = THEME_HIGHLIGHTED_COLOR
|
||||
@active_action_label.value = action.name
|
||||
|
||||
populate_variables_list(action)
|
||||
@@ -379,12 +404,14 @@ module TAC
|
||||
end
|
||||
end
|
||||
|
||||
caption "#{action.comment}", width: 1.0, text_wrap: :word_wrap unless action.comment.empty?
|
||||
unless action.comment.empty?
|
||||
stack(width: 1.0, fill: true, scroll: true) do
|
||||
caption action.comment.to_s, width: 1.0, text_wrap: :word_wrap, text_border: true, text_border_size: 1, text_border_color: 0xaa_000000
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
set_list_heights
|
||||
end
|
||||
|
||||
def populate_variables_list(action)
|
||||
@@ -394,12 +421,12 @@ module TAC
|
||||
|
||||
@variables_list.clear do
|
||||
variables.each_with_index do |variable, i|
|
||||
stack width: 1.0, **THEME_ITEM_CONTAINER_PADDING do
|
||||
stack width: 1.0, height: 96, **THEME_ITEM_CONTAINER_PADDING do
|
||||
background i.even? ? THEME_EVEN_COLOR : THEME_ODD_COLOR
|
||||
|
||||
flow(width: 1.0) do
|
||||
button "#{variable.name}", width: 0.89, tip: "Edit variable" do
|
||||
push_state(Dialog::VariableDialog, title: "Edit Variable", variable: variable, callback_method: method(:update_variable))
|
||||
flow(width: 1.0, fill: true) do
|
||||
button "#{variable.name}", fill: true, text_size: THEME_ICON_SIZE - 3, tip: "Edit variable" do
|
||||
push_state(Dialog::VariableDialog, title: "Edit Variable", variable: variable, list: @active_action.variables, callback_method: method(:update_variable))
|
||||
end
|
||||
|
||||
button get_image("#{TAC::ROOT_PATH}/media/icons/trashcan.png"), image_width: THEME_ICON_SIZE, tip: "Delete variable", **THEME_DANGER_BUTTON do
|
||||
@@ -412,8 +439,52 @@ module TAC
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
set_list_heights
|
||||
def button_down(id)
|
||||
super
|
||||
|
||||
return if control_down? || shift_down? || !alt_down?
|
||||
|
||||
case id
|
||||
when Gosu::KB_G
|
||||
push_state(
|
||||
TAC::Dialog::NamePromptDialog,
|
||||
title: "Create Group",
|
||||
list: window.backend.config.groups,
|
||||
callback_method: method(:create_group)
|
||||
)
|
||||
when Gosu::KB_A
|
||||
if @active_group
|
||||
push_state(
|
||||
TAC::Dialog::ActionDialog,
|
||||
title: "Create Action",
|
||||
list: @active_group.actions,
|
||||
callback_method: method(:create_action)
|
||||
)
|
||||
else
|
||||
push_state(
|
||||
TAC::Dialog::AlertDialog,
|
||||
title: "Error",
|
||||
message: "Unable to create action, no group selected."
|
||||
)
|
||||
end
|
||||
when Gosu::KB_V
|
||||
if @active_action
|
||||
push_state(
|
||||
TAC::Dialog::VariableDialog,
|
||||
title: "Create Variable",
|
||||
list: @active_action.variables,
|
||||
callback_method: method(:create_variable)
|
||||
)
|
||||
else
|
||||
push_state(
|
||||
TAC::Dialog::AlertDialog,
|
||||
title: "Error",
|
||||
message: "Unable to create variable, no action selected."
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -33,8 +33,15 @@ module TAC
|
||||
|
||||
button "Reset", text_size: THEME_HEADING_TEXT_SIZE, **THEME_DANGER_BUTTON do
|
||||
@nodes.clear
|
||||
measure_path
|
||||
|
||||
refresh_panel
|
||||
end
|
||||
|
||||
list_box items: ["Power Play", "Freight Frenzy", "Ultimate Goal", "Skystone"], width: 200, height: 1.0 do |item|
|
||||
season = item.downcase.gsub(" ", "_").to_sym
|
||||
@field = TAC::Simulator::Field.new(container: @field_container, season: season, simulation: nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -43,7 +50,7 @@ module TAC
|
||||
tagline "Nodes:"
|
||||
@nodes_count_label = tagline "0"
|
||||
|
||||
tagline "Total Distance:"
|
||||
tagline "Total Distance:", margin_left: 20
|
||||
@total_distance_label = tagline "0"
|
||||
|
||||
@units_label = tagline "Inches"
|
||||
@@ -61,7 +68,7 @@ module TAC
|
||||
end
|
||||
end
|
||||
|
||||
@field = TAC::Simulator::Field.new(container: @field_container, season: :freight_frenzy, simulation: nil)
|
||||
@field = TAC::Simulator::Field.new(container: @field_container, season: :power_play, simulation: nil)
|
||||
@nodes ||= []
|
||||
@unit = :inches
|
||||
@total_distance = 0
|
||||
@@ -72,21 +79,41 @@ module TAC
|
||||
@node_radius = 6
|
||||
@segment_thickness = 2
|
||||
|
||||
@font = CyberarmEngine::Text.new(font: THEME_BOLD_FONT, size: 18, border: true, static: true)
|
||||
|
||||
measure_path
|
||||
refresh_panel
|
||||
end
|
||||
|
||||
def draw
|
||||
super
|
||||
|
||||
@field.draw
|
||||
|
||||
display_path
|
||||
|
||||
if @field_container.hit?(window.mouse_x, window.mouse_y)
|
||||
x = (window.mouse_x - @field_container.x) / @field.scale - 72
|
||||
y = (window.mouse_y - @field_container.y) / @field.scale - 72
|
||||
|
||||
@font.text = "X: #{inches_to_unit(x).round(2)} Y: #{inches_to_unit(y).round(2)} (#{@unit.to_s})"
|
||||
@font.x = window.mouse_x + 6
|
||||
@font.y = window.mouse_y - (@font.height / 2.0 + 24)
|
||||
@font.z = 100_001
|
||||
|
||||
Gosu.draw_rect(
|
||||
window.mouse_x,
|
||||
@font.y - 6,
|
||||
@font.width + 12,
|
||||
@font.height + 12,
|
||||
0xaa_000000,
|
||||
100_000)
|
||||
|
||||
@font.draw
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def update
|
||||
super
|
||||
|
||||
@field.update
|
||||
|
||||
measure_path
|
||||
@@ -133,7 +160,7 @@ module TAC
|
||||
Gosu.draw_circle(
|
||||
current_node.x * @field.scale + @field_container.x,
|
||||
current_node.y * @field.scale + @field_container.y,
|
||||
@node_radius, 7, mouse_near ? @node_hover_color : @node_color, 10
|
||||
@node_radius, 7, mouse_near ? @node_hover_color : @node_color, @field_container.z + 1
|
||||
)
|
||||
|
||||
next if i.zero?
|
||||
@@ -153,7 +180,8 @@ module TAC
|
||||
(@field_container.y + last_node.y * @field.scale) - distance,
|
||||
@segment_thickness,
|
||||
distance,
|
||||
@segment_color
|
||||
@segment_color,
|
||||
@field_container.z + 1
|
||||
)
|
||||
end
|
||||
|
||||
@@ -184,6 +212,10 @@ module TAC
|
||||
@total_distance_label.value = "#{inches_to_unit(@total_distance).round(2)}"
|
||||
@units_label.value = @unit.to_s.capitalize
|
||||
|
||||
status_bar.recalculate
|
||||
status_bar.recalculate
|
||||
status_bar.recalculate
|
||||
|
||||
# @points_container.clear do
|
||||
# v1 = @nodes.first
|
||||
# break unless v1
|
||||
@@ -214,11 +246,11 @@ module TAC
|
||||
when :feet
|
||||
inches / 12.0
|
||||
when :millimeters
|
||||
inches / 0.254
|
||||
inches * 25.4
|
||||
when :centimeters
|
||||
inches / 2.54
|
||||
inches * 2.54
|
||||
when :meters
|
||||
inches / 25.4
|
||||
inches * 0.0254
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -34,9 +34,43 @@ module TAC
|
||||
label "Total actions: #{actions.size}"
|
||||
label "Total variables: #{variables.size}"
|
||||
end
|
||||
|
||||
stack(width: 1.0, fill: true, scroll: true, margin_top: 32) do
|
||||
heading, items = Gosu::LICENSES.split("\n\n")
|
||||
|
||||
title heading
|
||||
|
||||
items.split("\n").each do |item|
|
||||
name, website, license, license_website = item.split(",").map(&:strip)
|
||||
flow(width: 1.0, height: 28) do
|
||||
tagline "#{name} - "
|
||||
button "Website", height: 1.0, tip: website do
|
||||
open_url(website)
|
||||
end
|
||||
end
|
||||
|
||||
flow(width: 1.0, height: 22, margin_bottom: 20) do
|
||||
para "#{license} - "
|
||||
button "License Website", height: 1.0, text_size: 16, tip: license_website do
|
||||
open_url(license_website)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def open_url(url)
|
||||
case RUBY_PLATFORM
|
||||
when /mingw/ # windows
|
||||
system("start #{url}")
|
||||
when /linux/
|
||||
system("xdg-open #{url}")
|
||||
when /darwin/ # macos
|
||||
system("open #{url}")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -11,10 +11,10 @@ module TAC
|
||||
|
||||
body.clear do
|
||||
flow(width: 1.0, height: 1.0) do
|
||||
@group_presets = stack(width: 0.49995, height: 1.0, scroll: true, border_thickness_right: 1, border_color: [0, Gosu::Color::BLACK, 0, 0]) do
|
||||
@group_presets = stack(fill: true, height: 1.0, scroll: true, padding_left: 2, padding_top: 2, padding_right: 2, border_thickness_right: 1, border_color: Gosu::Color::BLACK) do
|
||||
end
|
||||
|
||||
@action_presets = stack(width: 0.49995, height: 1.0, scroll: true) do
|
||||
@action_presets = stack(fill: true, height: 1.0, scroll: true, padding_left: 2, padding_top: 2, padding_right: 2) do
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -26,11 +26,11 @@ module TAC
|
||||
def populate_group_presets
|
||||
@group_presets.clear do
|
||||
window.backend.config.presets.groups.each_with_index do |group, i|
|
||||
flow(width: 1.0, **THEME_ITEM_CONTAINER_PADDING) do
|
||||
flow(width: 1.0, height: 36, **THEME_ITEM_CONTAINER_PADDING) do
|
||||
background i.even? ? THEME_EVEN_COLOR : THEME_ODD_COLOR
|
||||
|
||||
button group.name, width: 0.895 do
|
||||
page(TAC::Pages::Editor,{ group: group, group_is_preset: true })
|
||||
button group.name, fill: true, text_size: THEME_ICON_SIZE - 3 do
|
||||
page(TAC::Pages::Editor, { group: group, group_is_preset: true })
|
||||
end
|
||||
|
||||
button get_image("#{TAC::ROOT_PATH}/media/icons/gear.png"), image_width: THEME_ICON_SIZE, tip: "Edit group preset" do
|
||||
@@ -59,11 +59,11 @@ module TAC
|
||||
def populate_action_presets
|
||||
@action_presets.clear do
|
||||
window.backend.config.presets.actions.each_with_index do |action, i|
|
||||
flow(width: 1.0, **THEME_ITEM_CONTAINER_PADDING) do
|
||||
flow(width: 1.0, height: 36, **THEME_ITEM_CONTAINER_PADDING) do
|
||||
background i.even? ? THEME_EVEN_COLOR : THEME_ODD_COLOR
|
||||
|
||||
button action.name, width: 0.895 do
|
||||
page(TAC::Pages::Editor,{ action: action, action_is_preset: true })
|
||||
button action.name, fill: true, text_size: THEME_ICON_SIZE - 3 do
|
||||
page(TAC::Pages::Editor, { action: action, action_is_preset: true })
|
||||
end
|
||||
|
||||
button get_image("#{TAC::ROOT_PATH}/media/icons/gear.png"), image_width: THEME_ICON_SIZE, tip: "Edit action preset" do
|
||||
|
||||
@@ -5,10 +5,10 @@ module TAC
|
||||
header_bar("Search")
|
||||
|
||||
menu_bar.clear do
|
||||
search = edit_line "", width: 0.9, height: 1.0
|
||||
search = edit_line "", fill: true, height: 1.0
|
||||
button get_image("#{TAC::ROOT_PATH}/media/icons/zoom.png"), image_height: 1.0 do
|
||||
unless search.value.strip.empty?
|
||||
search_results = search_config(search.value.downcase.strip)
|
||||
search_results = search_config(search.value.strip)
|
||||
|
||||
status_bar.clear do
|
||||
if search_results.results.size.zero?
|
||||
@@ -89,7 +89,6 @@ module TAC
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if search_results.action_presets.size.positive?
|
||||
title "Action Presets"
|
||||
|
||||
@@ -152,7 +151,7 @@ module TAC
|
||||
|
||||
def search_groups(query, search_results)
|
||||
window.backend.config.groups.each do |group|
|
||||
if group.name.downcase.include?(query)
|
||||
if group.name.downcase.include?(query.downcase)
|
||||
result = SearchResult.new(group: group, query: query, is_group: true, is_from_name: true)
|
||||
search_results.results << result
|
||||
end
|
||||
@@ -162,12 +161,12 @@ module TAC
|
||||
def search_actions(query, search_results)
|
||||
window.backend.config.groups.each do |group|
|
||||
group.actions.each do |action|
|
||||
if action.name.downcase.include?(query)
|
||||
if action.name.downcase.include?(query.downcase)
|
||||
result = SearchResult.new(group: group, action: action, query: query, is_action: true, is_from_name: true)
|
||||
search_results.results << result
|
||||
end
|
||||
|
||||
if action.comment.downcase.include?(query)
|
||||
if action.comment.downcase.include?(query.downcase)
|
||||
result = SearchResult.new(group: group, action: action, query: query, is_action: true, is_from_comment: true)
|
||||
search_results.results << result
|
||||
end
|
||||
@@ -179,12 +178,12 @@ module TAC
|
||||
window.backend.config.groups.each do |group|
|
||||
group.actions.each do |action|
|
||||
action.variables.each do |variable|
|
||||
if variable.name.downcase.include?(query)
|
||||
if variable.name.downcase.include?(query.downcase)
|
||||
result = SearchResult.new(group: group, action: action, variable: variable, is_variable: true, query: query, is_from_name: true)
|
||||
search_results.results << result
|
||||
end
|
||||
|
||||
if variable.value.downcase.include?(query)
|
||||
if variable.value.downcase.include?(query.downcase)
|
||||
result = SearchResult.new(group: group, action: action, variable: variable, is_variable: true, query: query, is_from_value: true)
|
||||
search_results.results << result
|
||||
end
|
||||
@@ -195,29 +194,29 @@ module TAC
|
||||
|
||||
def search_presets(query, search_results)
|
||||
window.backend.config.presets.groups.each do |group|
|
||||
if group.name.downcase.include?(query)
|
||||
if group.name.downcase.include?(query.downcase)
|
||||
result = SearchResult.new(group: group, query: query, is_group: true, is_from_name: true, is_preset: true)
|
||||
search_results.results << result
|
||||
end
|
||||
|
||||
group.actions.each do |action|
|
||||
if action.name.downcase.include?(query)
|
||||
if action.name.downcase.include?(query.downcase)
|
||||
result = SearchResult.new(group: group, action: action, query: query, is_action: true, is_from_name: true, is_preset: true)
|
||||
search_results.results << result
|
||||
end
|
||||
|
||||
if action.comment.downcase.include?(query)
|
||||
if action.comment.downcase.include?(query.downcase)
|
||||
result = SearchResult.new(group: group, action: action, query: query, is_action: true, is_from_comment: true, is_preset: true)
|
||||
search_results.results << result
|
||||
end
|
||||
|
||||
action.variables.each do |variable|
|
||||
if variable.name.downcase.include?(query)
|
||||
if variable.name.downcase.include?(query.downcase)
|
||||
result = SearchResult.new(group: group, action: action, variable: variable, is_variable: true, query: query, is_from_name: true, is_preset: true)
|
||||
search_results.results << result
|
||||
end
|
||||
|
||||
if variable.value.downcase.include?(query)
|
||||
if variable.value.downcase.include?(query.downcase)
|
||||
result = SearchResult.new(group: group, action: action, variable: variable, is_variable: true, query: query, is_from_value: true, is_preset: true)
|
||||
search_results.results << result
|
||||
end
|
||||
@@ -226,27 +225,27 @@ module TAC
|
||||
end
|
||||
|
||||
window.backend.config.presets.actions.each do |action|
|
||||
if action.name.downcase.include?(query)
|
||||
result = SearchResult.new(group: nil, action: action, query: query, is_action: true, is_from_name: true, is_preset: true)
|
||||
if action.name.downcase.include?(query.downcase)
|
||||
result = SearchResult.new(group: nil, action: action, query: query, is_action: true, is_from_name: true, is_preset: true)
|
||||
search_results.results << result
|
||||
end
|
||||
|
||||
if action.comment.downcase.include?(query.downcase)
|
||||
result = SearchResult.new(group: nil, action: action, query: query, is_action: true, is_from_comment: true, is_preset: true)
|
||||
search_results.results << result
|
||||
end
|
||||
|
||||
action.variables.each do |variable|
|
||||
if variable.name.downcase.include?(query.downcase)
|
||||
result = SearchResult.new(group: nil, action: action, variable: variable, is_variable: true, query: query, is_from_name: true, is_preset: true)
|
||||
search_results.results << result
|
||||
end
|
||||
|
||||
if action.comment.downcase.include?(query)
|
||||
result = SearchResult.new(group: nil, action: action, query: query, is_action: true, is_from_comment: true, is_preset: true)
|
||||
if variable.value.downcase.include?(query.downcase)
|
||||
result = SearchResult.new(group: nil, action: action, variable: variable, is_variable: true, query: query, is_from_value: true, is_preset: true)
|
||||
search_results.results << result
|
||||
end
|
||||
|
||||
action.variables.each do |variable|
|
||||
if variable.name.downcase.include?(query)
|
||||
result = SearchResult.new(group: nil, action: action, variable: variable, is_variable: true, query: query, is_from_name: true, is_preset: true)
|
||||
search_results.results << result
|
||||
end
|
||||
|
||||
if variable.value.downcase.include?(query)
|
||||
result = SearchResult.new(group: nil, action: action, variable: variable, is_variable: true, query: query, is_from_value: true, is_preset: true)
|
||||
search_results.results << result
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -332,7 +331,8 @@ module TAC
|
||||
end
|
||||
|
||||
def highlight(string)
|
||||
string.gsub(/#{@query}/i, "<b><c=ff00ff>#{@query}</c></b>")
|
||||
match = string.match(/#{@query}/i)
|
||||
string.gsub(/#{@query}/i, "<b><c=ff00ff>#{match}</c></b>")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -12,7 +12,7 @@ module TAC
|
||||
begin
|
||||
@simulation = TAC::Simulator::Simulation.new(source_code: @source_code.value, field_container: @field_container)
|
||||
@simulation.start
|
||||
rescue SyntaxError, NameError, NoMethodError, TypeError, ArgumentError => e
|
||||
rescue SyntaxError, NameError, NoMethodError, TypeError, ArgumentError, StandardError => e
|
||||
puts e.backtrace.reverse.join("\n")
|
||||
puts e
|
||||
push_state(Dialog::AlertDialog, title: "#{e.class}", message: e)
|
||||
@@ -49,7 +49,7 @@ robot.forward 100
|
||||
robot.turn -90
|
||||
robot.forward 100"
|
||||
|
||||
source_code = File.read(SOURCE_FILE_PATH) if File.exists?(SOURCE_FILE_PATH)
|
||||
source_code = File.read(SOURCE_FILE_PATH) if File.exist?(SOURCE_FILE_PATH)
|
||||
|
||||
@source_code = edit_box source_code, width: 1.0, height: 1.0
|
||||
end
|
||||
@@ -77,6 +77,7 @@ robot.forward 100"
|
||||
@simulation.update
|
||||
|
||||
unless @simulation.robots.all? { |robot| robot.queue.empty? } # Only update clock if simulation is running
|
||||
current_state.request_repaint
|
||||
@simulation_status.value = "Time: #{(@simulation.simulation_time).round(1)} seconds"
|
||||
end
|
||||
end
|
||||
|
||||
@@ -12,14 +12,14 @@ module TAC
|
||||
@scale = 1
|
||||
@size = 0
|
||||
@field_size = 144 # inches [1 pixel = 1 inch]
|
||||
@z = @container.z + 1
|
||||
|
||||
@blue = Gosu::Color.new(0xff_004080)
|
||||
@red = Gosu::Color.new(0xff_800000)
|
||||
@soft_orange = Gosu::Color.rgb(255, 175, 0)
|
||||
end
|
||||
|
||||
def draw
|
||||
Gosu.flush
|
||||
|
||||
Gosu.clip_to(@position.x, @position.y, @size, @size) do
|
||||
Gosu.translate(@position.x, @position.y) do
|
||||
draw_field
|
||||
@@ -34,88 +34,90 @@ module TAC
|
||||
end
|
||||
|
||||
def draw_field
|
||||
Gosu.draw_rect(0, 0, @field_size * @scale, @field_size * @scale, Gosu::Color::GRAY)
|
||||
Gosu.draw_rect(0, 0, @field_size * @scale, @field_size * @scale, Gosu::Color::GRAY, @z)
|
||||
6.times do |i| # Tile lines across
|
||||
next if i == 0
|
||||
Gosu.draw_rect((@field_size * @scale) / 6 * i, 0, 1, @field_size * @scale, Gosu::Color::BLACK)
|
||||
Gosu.draw_rect((@field_size * @scale) / 6 * i, 0, 1, @field_size * @scale, Gosu::Color::BLACK, @z)
|
||||
end
|
||||
6.times do |i| # Tile lines down
|
||||
next if i == 0
|
||||
Gosu.draw_rect(0, (@field_size * @scale) / 6 * i, @field_size * @scale, 1, Gosu::Color::BLACK)
|
||||
Gosu.draw_rect(0, (@field_size * @scale) / 6 * i, @field_size * @scale, 1, Gosu::Color::BLACK, @z)
|
||||
end
|
||||
end
|
||||
|
||||
def draw_field_skystone
|
||||
# blue bridge
|
||||
Gosu.draw_rect(0, @field_size / 2 - 2, 48, 1, @blue)
|
||||
Gosu.draw_rect(0, @field_size / 2 + 1, 48, 1, @blue)
|
||||
Gosu.draw_rect(0, @field_size / 2 - 2, 48, 1, @blue, @z)
|
||||
Gosu.draw_rect(0, @field_size / 2 + 1, 48, 1, @blue, @z)
|
||||
|
||||
# mid bridge
|
||||
Gosu.draw_rect(@field_size / 2 - 24, @field_size / 2 - 9.25, 48, 18.5, Gosu::Color.new(0xff_222222))
|
||||
Gosu.draw_rect(@field_size / 2 - 24, @field_size / 2 - 2, 48, 1, Gosu::Color::YELLOW)
|
||||
Gosu.draw_rect(@field_size / 2 - 24, @field_size / 2 + 1, 48, 1, Gosu::Color::YELLOW)
|
||||
Gosu.draw_rect(@field_size / 2 - 24, @field_size / 2 - 9.25, 48, 18.5, Gosu::Color.new(0xff_222222), @z)
|
||||
Gosu.draw_rect(@field_size / 2 - 24, @field_size / 2 - 2, 48, 1, @soft_orange, @z)
|
||||
Gosu.draw_rect(@field_size / 2 - 24, @field_size / 2 + 1, 48, 1, @soft_orange, @z)
|
||||
|
||||
# blue bridge
|
||||
Gosu.draw_rect(@field_size - 48, @field_size / 2 - 2, 48, 1, @red)
|
||||
Gosu.draw_rect(@field_size - 48, @field_size / 2 + 1, 48, 1, @red)
|
||||
Gosu.draw_rect(@field_size - 48, @field_size / 2 - 2, 48, 1, @red, @z)
|
||||
Gosu.draw_rect(@field_size - 48, @field_size / 2 + 1, 48, 1, @red, @z)
|
||||
|
||||
# blue build site
|
||||
Gosu.draw_quad(
|
||||
24 - 2, 0, @blue,
|
||||
24, 0, @blue,
|
||||
0, 24 - 2, @blue,
|
||||
0, 24, @blue
|
||||
)
|
||||
0, 24, @blue,
|
||||
@z
|
||||
)
|
||||
|
||||
# red build site
|
||||
Gosu.draw_quad(
|
||||
@field_size - (24 - 2), 0, @red,
|
||||
@field_size - (24 - 0), 0, @red,
|
||||
@field_size, 24 - 2, @red,
|
||||
@field_size, 24, @red
|
||||
)
|
||||
@field_size, 24, @red,
|
||||
@z
|
||||
)
|
||||
|
||||
# blue depot
|
||||
Gosu.draw_rect(@field_size - 24, @field_size - 24, 24, 2, @blue)
|
||||
Gosu.draw_rect(@field_size - 24, @field_size - 24, 2, 24, @blue)
|
||||
Gosu.draw_rect(@field_size - 24, @field_size - 24, 24, 2, @blue, @z)
|
||||
Gosu.draw_rect(@field_size - 24, @field_size - 24, 2, 24, @blue, @z)
|
||||
|
||||
# red depot
|
||||
Gosu.draw_rect(-1, @field_size - 24, 24, 2, @red)
|
||||
Gosu.draw_rect(22, @field_size - 24, 2, 24, @red)
|
||||
Gosu.draw_rect(-1, @field_size - 24, 24, 2, @red, @z)
|
||||
Gosu.draw_rect(22, @field_size - 24, 2, 24, @red, @z)
|
||||
|
||||
# blue foundation
|
||||
Gosu.draw_rect(48, 4, 18.5, 34.5, @blue)
|
||||
Gosu.draw_rect(48, 4, 18.5, 34.5, @blue, @z)
|
||||
|
||||
# red foundation
|
||||
Gosu.draw_rect(@field_size - (48 + 18.5), 4, 18.5, 34.5, @red)
|
||||
Gosu.draw_rect(@field_size - (48 + 18.5), 4, 18.5, 34.5, @red, @z)
|
||||
|
||||
# stones
|
||||
6.times do |i|
|
||||
Gosu.draw_rect(48, @field_size - 8 * i - 8, 4, 8, Gosu::Color::YELLOW)
|
||||
Gosu.draw_rect(48, @field_size - 8 * i - 8, 4, 8, @soft_orange, @z)
|
||||
end
|
||||
6.times do |i|
|
||||
Gosu.draw_rect(@field_size - (48 + 4), @field_size - 8 * i - 8, 4, 8, Gosu::Color::YELLOW)
|
||||
Gosu.draw_rect(@field_size - (48 + 4), @field_size - 8 * i - 8, 4, 8, @soft_orange, @z)
|
||||
end
|
||||
end
|
||||
|
||||
def draw_field_ultimate_goal
|
||||
# middle line
|
||||
Gosu.draw_rect(0, @field_size / 2 - 13, @field_size, 2, Gosu::Color::WHITE)
|
||||
Gosu.draw_rect(0, @field_size / 2 - 13, @field_size, 2, Gosu::Color::WHITE, @z)
|
||||
|
||||
# phantom center line to indict half field for remote season field
|
||||
Gosu.draw_rect(@field_size / 2 - (0.5 + 24), 0, 1, @field_size, 0x88_448844)
|
||||
Gosu.draw_rect(@field_size / 2 - (0.5 + 24), 0, 1, @field_size, 0x88_448844, @z)
|
||||
|
||||
|
||||
# blue starting lines
|
||||
Gosu.draw_rect(24 - 1, @field_size - 24, 2, 24, @blue)
|
||||
Gosu.draw_rect(48 - 1, @field_size - 24, 2, 24, @blue)
|
||||
Gosu.draw_rect(24 - 1, @field_size - 24, 2, 24, @blue, @z)
|
||||
Gosu.draw_rect(48 - 1, @field_size - 24, 2, 24, @blue, @z)
|
||||
|
||||
# blue wobbly wobs
|
||||
Gosu.draw_circle(24, @field_size - 24, 4, 32, @blue)
|
||||
Gosu.draw_circle(48, @field_size - 24, 4, 32, @blue)
|
||||
Gosu.draw_circle(24, @field_size - 24, 4, 32, @blue, @z)
|
||||
Gosu.draw_circle(48, @field_size - 24, 4, 32, @blue, @z)
|
||||
|
||||
# blue starter stack
|
||||
Gosu.draw_rect(36 - 1, @field_size - 50, 2, 2, @blue)
|
||||
Gosu.draw_rect(36 - 1, @field_size - 50, 2, 2, @blue, @z)
|
||||
|
||||
# blue target zones
|
||||
# A
|
||||
@@ -132,15 +134,15 @@ module TAC
|
||||
end
|
||||
|
||||
# red starting lines
|
||||
Gosu.draw_rect(@field_size - 24 - 1, @field_size - 24, 2, 24, @red)
|
||||
Gosu.draw_rect(@field_size - 48 - 1, @field_size - 24, 2, 24, @red)
|
||||
Gosu.draw_rect(@field_size - 24 - 1, @field_size - 24, 2, 24, @red, @z)
|
||||
Gosu.draw_rect(@field_size - 48 - 1, @field_size - 24, 2, 24, @red, @z)
|
||||
|
||||
# red wobbly wobs
|
||||
Gosu.draw_circle(@field_size - 24, @field_size - 24, 4, 32, @red)
|
||||
Gosu.draw_circle(@field_size - 48, @field_size - 24, 4, 32, @red)
|
||||
Gosu.draw_circle(@field_size - 24, @field_size - 24, 4, 32, @red, @z)
|
||||
Gosu.draw_circle(@field_size - 48, @field_size - 24, 4, 32, @red, @z)
|
||||
|
||||
# red starter stack
|
||||
Gosu.draw_rect(@field_size - 37, @field_size - 50, 2, 2, @red)
|
||||
Gosu.draw_rect(@field_size - 37, @field_size - 50, 2, 2, @red, @z)
|
||||
|
||||
# red target zones
|
||||
# A
|
||||
@@ -161,91 +163,88 @@ module TAC
|
||||
|
||||
def draw_field_freight_frenzy
|
||||
# blue ZONE
|
||||
Gosu.draw_rect(24, @field_size - 24, 2, 24, @blue)
|
||||
Gosu.draw_rect(24, @field_size - 24, 24, 2, @blue)
|
||||
Gosu.draw_rect(48 - 2, @field_size - 24, 2, 24, @blue)
|
||||
Gosu.draw_rect(24, @field_size - 24, 2, 24, @blue, @z)
|
||||
Gosu.draw_rect(24, @field_size - 24, 24, 2, @blue, @z)
|
||||
Gosu.draw_rect(48 - 2, @field_size - 24, 2, 24, @blue, @z)
|
||||
|
||||
# blue barcode 1
|
||||
Gosu.draw_rect(36 - 1, @field_size - 24 - 4, 2, 2, @blue)
|
||||
Gosu.draw_rect(36 - 1, @field_size - 36 - 1, 2, 2, @blue)
|
||||
Gosu.draw_rect(36 - 1, @field_size - 48 + 2, 2, 2, @blue)
|
||||
Gosu.draw_rect(36 - 1, @field_size - 24 - 4, 2, 2, @blue, @z)
|
||||
Gosu.draw_rect(36 - 1, @field_size - 36 - 1, 2, 2, @blue, @z)
|
||||
Gosu.draw_rect(36 - 1, @field_size - 48 + 2, 2, 2, @blue, @z)
|
||||
|
||||
# blue barcode 2
|
||||
Gosu.draw_rect(36 - 1, 48 + 2, 2, 2, @blue)
|
||||
Gosu.draw_rect(36 - 1, 60 - 1, 2, 2, @blue)
|
||||
Gosu.draw_rect(36 - 1, 72 - 4, 2, 2, @blue)
|
||||
Gosu.draw_rect(36 - 1, 48 + 2, 2, 2, @blue, @z)
|
||||
Gosu.draw_rect(36 - 1, 60 - 1, 2, 2, @blue, @z)
|
||||
Gosu.draw_rect(36 - 1, 72 - 4, 2, 2, @blue, @z)
|
||||
|
||||
# blue wobble goal
|
||||
Gosu.draw_circle(48, 84, 9, 32, @blue)
|
||||
Gosu.draw_circle(48, 84, 9, 32, @blue, @z)
|
||||
|
||||
# blue shared wobble goal
|
||||
Gosu.draw_circle(@field_size / 2, 24, 9, 32, @blue)
|
||||
Gosu.draw_circle(@field_size / 2, 24, 9, 32, @blue, @z)
|
||||
|
||||
# red ZONE
|
||||
Gosu.draw_rect(@field_size - 24 - 2, @field_size - 24, 2, 24, @red)
|
||||
Gosu.draw_rect(@field_size - 48, @field_size - 24, 24, 2, @red)
|
||||
Gosu.draw_rect(@field_size - 48, @field_size - 24, 2, 24, @red)
|
||||
Gosu.draw_rect(@field_size - 24 - 2, @field_size - 24, 2, 24, @red, @z)
|
||||
Gosu.draw_rect(@field_size - 48, @field_size - 24, 24, 2, @red, @z)
|
||||
Gosu.draw_rect(@field_size - 48, @field_size - 24, 2, 24, @red, @z)
|
||||
|
||||
# red barcode 1
|
||||
Gosu.draw_rect(@field_size - 36 - 1, @field_size - 24 - 4, 2, 2, @red)
|
||||
Gosu.draw_rect(@field_size - 36 - 1, @field_size - 36 - 1, 2, 2, @red)
|
||||
Gosu.draw_rect(@field_size - 36 - 1, @field_size - 48 + 2, 2, 2, @red)
|
||||
Gosu.draw_rect(@field_size - 36 - 1, @field_size - 24 - 4, 2, 2, @red, @z)
|
||||
Gosu.draw_rect(@field_size - 36 - 1, @field_size - 36 - 1, 2, 2, @red, @z)
|
||||
Gosu.draw_rect(@field_size - 36 - 1, @field_size - 48 + 2, 2, 2, @red, @z)
|
||||
|
||||
# red barcode 2
|
||||
Gosu.draw_rect(@field_size - 36 - 1, 48 + 2, 2, 2, @red)
|
||||
Gosu.draw_rect(@field_size - 36 - 1, 60 - 1, 2, 2, @red)
|
||||
Gosu.draw_rect(@field_size - 36 - 1, 72 - 4, 2, 2, @red)
|
||||
Gosu.draw_rect(@field_size - 36 - 1, 48 + 2, 2, 2, @red, @z)
|
||||
Gosu.draw_rect(@field_size - 36 - 1, 60 - 1, 2, 2, @red, @z)
|
||||
Gosu.draw_rect(@field_size - 36 - 1, 72 - 4, 2, 2, @red, @z)
|
||||
|
||||
# red wobble goal
|
||||
Gosu.draw_circle(@field_size - 48, 84, 9, 32, @red)
|
||||
Gosu.draw_circle(@field_size - 48, 84, 9, 32, @red, @z)
|
||||
|
||||
# red shared wobble goal
|
||||
Gosu.clip_to(@field_size / 2, 0, 10, 48) do
|
||||
Gosu.draw_circle(@field_size / 2, 24, 9, 32, @red)
|
||||
end
|
||||
# Gosu.clip_to(@field_size / 2, 0, 10, 48) do
|
||||
Gosu.draw_circle(@field_size / 2, 24, 9, 32, @red, @z)
|
||||
# end
|
||||
|
||||
# white corner left
|
||||
faint_white = Gosu::Color.rgb(240, 240, 240)
|
||||
|
||||
Gosu.draw_rect(0, 46 - 2, 46, 2, faint_white)
|
||||
Gosu.draw_rect(46 - 2, 0, 2, 46, faint_white)
|
||||
Gosu.draw_rect(0, 46 - 2, 46, 2, faint_white, @z)
|
||||
Gosu.draw_rect(46 - 2, 0, 2, 46, faint_white, @z)
|
||||
# white corner right
|
||||
Gosu.draw_rect(@field_size - 46, 46 - 2, 46, 2, faint_white)
|
||||
Gosu.draw_rect(@field_size - 46, 0, 2, 46, faint_white)
|
||||
Gosu.draw_rect(@field_size - 46, 46 - 2, 46, 2, faint_white, @z)
|
||||
Gosu.draw_rect(@field_size - 46, 0, 2, 46, faint_white, @z)
|
||||
|
||||
# cross bars
|
||||
bar_gray = Gosu::Color.rgb(50, 50, 50)
|
||||
# MAIN
|
||||
Gosu.draw_rect(13.75, 48 - 2, @field_size - 13.75 * 2, 1, bar_gray)
|
||||
Gosu.draw_rect(13.75, 48 + 1, @field_size - 13.75 * 2, 1, bar_gray)
|
||||
Gosu.draw_rect(13.75, 48 - 2, 1, 4, Gosu::Color::BLACK)
|
||||
Gosu.draw_rect(@field_size - 13.75 - 1, 48 - 2, 1, 4, Gosu::Color::BLACK)
|
||||
Gosu.draw_rect(13.75, 48 - 2, @field_size - 13.75 * 2, 1, bar_gray, @z)
|
||||
Gosu.draw_rect(13.75, 48 + 1, @field_size - 13.75 * 2, 1, bar_gray, @z)
|
||||
Gosu.draw_rect(13.75, 48 - 2, 1, 4, Gosu::Color::BLACK, @z)
|
||||
Gosu.draw_rect(@field_size - 13.75 - 1, 48 - 2, 1, 4, Gosu::Color::BLACK, @z)
|
||||
|
||||
# BLUE
|
||||
Gosu.draw_rect(48 - 2, 13.75, 1, 48 - 13.75 - 2, bar_gray)
|
||||
Gosu.draw_rect(48 + 1, 13.75, 1, 48 - 13.75 - 2, bar_gray)
|
||||
Gosu.draw_rect(48 - 2, 13.75, 4, 1, Gosu::Color::BLACK)
|
||||
Gosu.draw_rect(48 - 2, 48 - 3, 4, 1, Gosu::Color::BLACK)
|
||||
Gosu.draw_rect(48 - 2, 13.75, 1, 48 - 13.75 - 2, bar_gray, @z)
|
||||
Gosu.draw_rect(48 + 1, 13.75, 1, 48 - 13.75 - 2, bar_gray, @z)
|
||||
Gosu.draw_rect(48 - 2, 13.75, 4, 1, Gosu::Color::BLACK, @z)
|
||||
Gosu.draw_rect(48 - 2, 48 - 3, 4, 1, Gosu::Color::BLACK, @z)
|
||||
|
||||
# RED
|
||||
Gosu.draw_rect(@field_size - 48 - 2, 13.75, 1, 48 - 13.75 - 2, bar_gray)
|
||||
Gosu.draw_rect(@field_size - 48 + 1, 13.75, 1, 48 - 13.75 - 2, bar_gray)
|
||||
Gosu.draw_rect(@field_size - 48 - 2, 13.75, 4, 1, Gosu::Color::BLACK)
|
||||
Gosu.draw_rect(@field_size - 48 - 2, 48 - 3, 4, 1, Gosu::Color::BLACK)
|
||||
Gosu.draw_rect(@field_size - 48 - 2, 13.75, 1, 48 - 13.75 - 2, bar_gray, @z)
|
||||
Gosu.draw_rect(@field_size - 48 + 1, 13.75, 1, 48 - 13.75 - 2, bar_gray, @z)
|
||||
Gosu.draw_rect(@field_size - 48 - 2, 13.75, 4, 1, Gosu::Color::BLACK, @z)
|
||||
Gosu.draw_rect(@field_size - 48 - 2, 48 - 3, 4, 1, Gosu::Color::BLACK, @z)
|
||||
|
||||
# Duck Delivery
|
||||
Gosu.draw_circle(2, @field_size - 2, 9, 16, Gosu::Color.rgb(75, 75, 75))
|
||||
Gosu.draw_circle(@field_size - 2, @field_size - 2, 9, 16, Gosu::Color.rgb(75, 75, 75))
|
||||
|
||||
# packages
|
||||
soft_orange = Gosu::Color.rgb(255, 175, 0)
|
||||
|
||||
7.times do |y|
|
||||
7.times do |x|
|
||||
if x.even?
|
||||
Gosu.draw_rect(x * 3 + 1, y * 3 + 1, 2, 2, soft_orange)
|
||||
Gosu.draw_rect(x * 3 + 1, y * 3 + 1, 2, 2, @soft_orange, @z)
|
||||
else
|
||||
Gosu.draw_circle(x * 3 + 2, y * 3 + 2, 1, 16, faint_white)
|
||||
Gosu.draw_circle(x * 3 + 2, y * 3 + 2, 1, 16, faint_white, @z)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -253,24 +252,95 @@ module TAC
|
||||
7.times do |y|
|
||||
7.times do |x|
|
||||
if x.even?
|
||||
Gosu.draw_rect((@field_size - 4) - x * 3 + 1, y * 3 + 1, 2, 2, soft_orange)
|
||||
Gosu.draw_rect((@field_size - 4) - x * 3 + 1, y * 3 + 1, 2, 2, @soft_orange, @z)
|
||||
else
|
||||
Gosu.draw_circle((@field_size - 4) - x * 3 + 2, y * 3 + 2, 1, 16, faint_white)
|
||||
Gosu.draw_circle((@field_size - 4) - x * 3 + 2, y * 3 + 2, 1, 16, faint_white, @z)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Gosu.draw_rect(0, 60 - 1, 2, 2, soft_orange)
|
||||
Gosu.draw_rect(0, 108 - 1, 2, 2, soft_orange)
|
||||
Gosu.draw_rect(@field_size - 2, 60 - 1, 2, 2, soft_orange)
|
||||
Gosu.draw_rect(@field_size - 2, 108 - 1, 2, 2, soft_orange)
|
||||
Gosu.draw_rect(0, 60 - 1, 2, 2, @soft_orange, @z)
|
||||
Gosu.draw_rect(0, 108 - 1, 2, 2, @soft_orange, @z)
|
||||
Gosu.draw_rect(@field_size - 2, 60 - 1, 2, 2, @soft_orange, @z)
|
||||
Gosu.draw_rect(@field_size - 2, 108 - 1, 2, 2, @soft_orange, @z)
|
||||
end
|
||||
|
||||
def draw_field_power_play
|
||||
# pole junctions (Drawn before ground junctions to be lazy- ground junctions will cover non-existant poles)
|
||||
5.times do |y|
|
||||
5.times do |x|
|
||||
Gosu.draw_circle(24 + (x * 24), 24 + (y * 24), 0.5, 16, @soft_orange, @z)
|
||||
end
|
||||
end
|
||||
|
||||
# ground junction
|
||||
3.times do |y|
|
||||
3.times do |x|
|
||||
Gosu.draw_circle(24 + (x * 48), 24 + (y * 48), 3, 16, Gosu::Color::BLACK, @z)
|
||||
end
|
||||
end
|
||||
|
||||
# Field cones
|
||||
2.times do |y|
|
||||
2.times do |x|
|
||||
Gosu.draw_circle(36 + (x * 72), 36 + (y * 72), 2, 16, x.zero? ? @blue : @red, @z)
|
||||
end
|
||||
end
|
||||
|
||||
# alliance LINEs
|
||||
2.times do |y|
|
||||
2.times do |x|
|
||||
Gosu.draw_rect(59 + (x * 24), y * (144 - 23.5), 2, 23.5, x.zero? ? @blue : @red, @z)
|
||||
end
|
||||
end
|
||||
|
||||
# alliance LINE cones
|
||||
2.times do |y|
|
||||
2.times do |x|
|
||||
Gosu.draw_circle(60 + (x * 24), y * (144 - 4) + 2, 2, 16, x.zero? ? @blue : @red, @z)
|
||||
end
|
||||
end
|
||||
|
||||
# Corner TAPE
|
||||
4.times do |i|
|
||||
Gosu.rotate(i * 90.0, 72, 72) do
|
||||
Gosu.draw_quad(
|
||||
24 - 2, 0, i.even? ? @red : @blue,
|
||||
24, 0, i.even? ? @red : @blue,
|
||||
0, 24 - 2, i.even? ? @red : @blue,
|
||||
0, 24, i.even? ? @red : @blue,
|
||||
@z
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
# Triangle TAPE
|
||||
2.times do |i|
|
||||
Gosu.rotate(i * 180.0, 72, 72) do
|
||||
Gosu.draw_quad(
|
||||
0, 72 - 10.5, i.odd? ? @red : @blue,
|
||||
10.5, 72, i.odd? ? @red : @blue,
|
||||
8.5, 72, i.odd? ? @red : @blue,
|
||||
0, 72 - 8.5, i.odd? ? @red : @blue,
|
||||
@z
|
||||
)
|
||||
|
||||
Gosu.draw_quad(
|
||||
0, 72 + 10.5, i.odd? ? @red : @blue,
|
||||
10.5, 72, i.odd? ? @red : @blue,
|
||||
8.5, 72, i.odd? ? @red : @blue,
|
||||
0, 72 + 8.5, i.odd? ? @red : @blue,
|
||||
@z
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def draw_tile_box(color)
|
||||
Gosu.draw_rect(0, 0, 24, 2, color)
|
||||
Gosu.draw_rect(22, 2, 2, 22, color)
|
||||
Gosu.draw_rect(0, 22, 22, 2, color)
|
||||
Gosu.draw_rect(0, 2, 2, 22, color)
|
||||
Gosu.draw_rect(0, 0, 24, 2, color, @z)
|
||||
Gosu.draw_rect(22, 2, 2, 22, color, @z)
|
||||
Gosu.draw_rect(0, 22, 22, 2, color, @z)
|
||||
Gosu.draw_rect(0, 2, 2, 22, color, @z)
|
||||
end
|
||||
|
||||
def update
|
||||
|
||||
@@ -1,44 +1,54 @@
|
||||
module TAC
|
||||
class Simulator
|
||||
class Robot
|
||||
attr_accessor :position, :angle
|
||||
attr_reader :alliance, :width, :depth
|
||||
def initialize(alliance:, width:, depth:)
|
||||
FONT = Gosu::Font.new(11)
|
||||
|
||||
attr_accessor :position, :angle, :comment
|
||||
attr_reader :alliance, :width, :depth, :z
|
||||
def initialize(alliance:, width:, depth:, container:)
|
||||
@alliance = alliance
|
||||
@width, @depth = width, depth
|
||||
@width = width
|
||||
@depth = depth
|
||||
@container = container
|
||||
|
||||
@position = CyberarmEngine::Vector.new
|
||||
@angle = 0
|
||||
@z = @container.z + 1
|
||||
|
||||
@queue = []
|
||||
|
||||
@unit = :ticks
|
||||
@ticks_per_revolution = 240
|
||||
@gear_ratio = 1
|
||||
|
||||
@comment = ""
|
||||
end
|
||||
|
||||
def draw
|
||||
Gosu.translate(@width / 2, @depth / 2) do
|
||||
Gosu.rotate(@angle, @position.x, @position.y) do
|
||||
Gosu.draw_rect(@position.x - @width / 2, @position.y - @depth / 2, @width, @depth, Gosu::Color::BLACK)
|
||||
Gosu.draw_rect(@position.x - @width / 2 + 1, @position.y - @depth / 2 + 1, @width - 2, @depth - 2, Gosu::Color.new(0xff_808022))
|
||||
Gosu.draw_rect(@position.x - @width / 2, @position.y - @depth / 2, @width, @depth, Gosu::Color::BLACK, @z)
|
||||
Gosu.draw_rect(@position.x - @width / 2 + 1, @position.y - @depth / 2 + 1, @width - 2, @depth - 2, Gosu::Color.new(0xff_808022), @z)
|
||||
|
||||
if @alliance == :blue
|
||||
Gosu.draw_arc(@position.x, @position.y, 6, 1.0, 32, 2, TAC::Palette::BLUE_ALLIANCE)
|
||||
Gosu.draw_arc(@position.x, @position.y, 6, 1.0, 32, 2, TAC::Palette::BLUE_ALLIANCE, @z)
|
||||
elsif @alliance == :red
|
||||
Gosu.draw_arc(@position.x, @position.y, 6, 1.0, 32, 2, TAC::Palette::RED_ALLIANCE)
|
||||
Gosu.draw_arc(@position.x, @position.y, 6, 1.0, 32, 2, TAC::Palette::RED_ALLIANCE, @z)
|
||||
else
|
||||
Gosu.draw_arc(@position.x, @position.y, 6, 1.0, 32, 2, @alliance)
|
||||
Gosu.draw_arc(@position.x, @position.y, 6, 1.0, 32, 2, @alliance, @z)
|
||||
end
|
||||
Gosu.draw_circle(@position.x, @position.y - @depth * 0.25, 2, 3, TAC::Palette::TIMECRAFTERS_TERTIARY)
|
||||
Gosu.draw_circle(@position.x, @position.y - @depth * 0.25, 2, 3, TAC::Palette::TIMECRAFTERS_TERTIARY, @z)
|
||||
end
|
||||
|
||||
FONT.draw_text(@comment, 2.2, 2.2, @z, 1, 1, Gosu::Color::BLACK)
|
||||
FONT.draw_text(@comment, 2, 2, @z)
|
||||
end
|
||||
end
|
||||
|
||||
def update(dt)
|
||||
@angle %= 360.0
|
||||
|
||||
if state = @queue.first
|
||||
if (state = @queue.first)
|
||||
state.update(dt)
|
||||
|
||||
if state.complete?
|
||||
@@ -87,6 +97,14 @@ module TAC
|
||||
@queue << Turn.new(robot: self, relative_angle: relative_angle, power: power)
|
||||
end
|
||||
|
||||
def delay(time_in_seconds)
|
||||
@queue << Delay.new(robot: self, time_in_seconds: time_in_seconds)
|
||||
end
|
||||
|
||||
def comment(comment)
|
||||
@queue << Comment.new(robot: self, comment: comment)
|
||||
end
|
||||
|
||||
def speed
|
||||
@ticks_per_revolution / @gear_ratio
|
||||
end
|
||||
@@ -95,7 +113,7 @@ module TAC
|
||||
@queue
|
||||
end
|
||||
|
||||
class State
|
||||
class State
|
||||
def start
|
||||
end
|
||||
|
||||
@@ -130,9 +148,10 @@ class State
|
||||
def draw
|
||||
Gosu.draw_line(
|
||||
@robot.position.x + @robot.width / 2, @robot.position.y + @robot.depth / 2, TAC::Palette::TIMECRAFTERS_TERTIARY,
|
||||
@goal.x + @robot.width / 2, @goal.y + @robot.depth / 2, TAC::Palette::TIMECRAFTERS_TERTIARY
|
||||
@goal.x + @robot.width / 2, @goal.y + @robot.depth / 2, TAC::Palette::TIMECRAFTERS_TERTIARY,
|
||||
@robot.z
|
||||
)
|
||||
Gosu.draw_rect(@goal.x + (@robot.width / 2 - 1), @goal.y + (@robot.depth / 2 - 1), 2, 2, Gosu::Color::RED)
|
||||
Gosu.draw_rect(@goal.x + (@robot.width / 2 - 1), @goal.y + (@robot.depth / 2 - 1), 2, 2, Gosu::Color::RED, @robot.z)
|
||||
end
|
||||
|
||||
def update(dt)
|
||||
@@ -176,9 +195,10 @@ class State
|
||||
def draw
|
||||
Gosu.draw_line(
|
||||
@robot.position.x + @robot.width / 2, @robot.position.y + @robot.depth / 2, TAC::Palette::TIMECRAFTERS_TERTIARY,
|
||||
@goal.x + @robot.width / 2, @goal.y + @robot.depth / 2, TAC::Palette::TIMECRAFTERS_TERTIARY
|
||||
@goal.x + @robot.width / 2, @goal.y + @robot.depth / 2, TAC::Palette::TIMECRAFTERS_TERTIARY,
|
||||
@robot.z
|
||||
)
|
||||
Gosu.draw_rect(@goal.x + (@robot.width / 2 - 1), @goal.y + (@robot.depth / 2 - 1), 2, 2, Gosu::Color::RED)
|
||||
Gosu.draw_rect(@goal.x + (@robot.width / 2 - 1), @goal.y + (@robot.depth / 2 - 1), 2, 2, Gosu::Color::RED, @robot.z)
|
||||
end
|
||||
|
||||
def update(dt)
|
||||
@@ -230,7 +250,8 @@ class State
|
||||
fraction,
|
||||
360,
|
||||
1,
|
||||
TAC::Palette::TIMECRAFTERS_TERTIARY
|
||||
TAC::Palette::TIMECRAFTERS_TERTIARY,
|
||||
@robot.z
|
||||
)
|
||||
end
|
||||
|
||||
@@ -239,7 +260,8 @@ class State
|
||||
@robot.position.y + @robot.depth / 2 + Gosu.offset_y(@target_angle, @robot.width > @robot.depth ? @robot.width : @robot.depth),
|
||||
1,
|
||||
9,
|
||||
Gosu::Color::RED
|
||||
Gosu::Color::RED,
|
||||
@robot.z
|
||||
)
|
||||
# Gosu.draw_arc(@position.x, @position.y, 6, 1.0, 32, 2, @alliance)
|
||||
end
|
||||
@@ -259,6 +281,58 @@ class State
|
||||
@last_angle = @robot.angle
|
||||
end
|
||||
end
|
||||
|
||||
class Delay < State
|
||||
def initialize(robot:, time_in_seconds:)
|
||||
@robot = robot
|
||||
@time_in_seconds = time_in_seconds
|
||||
|
||||
@accumulator = 0.0
|
||||
end
|
||||
|
||||
def start
|
||||
@complete = false
|
||||
end
|
||||
|
||||
def draw
|
||||
fraction = @accumulator / @time_in_seconds.to_f
|
||||
|
||||
Gosu.draw_arc(
|
||||
@robot.position.x + @robot.width / 2,
|
||||
@robot.position.y + @robot.depth / 2,
|
||||
@robot.width > @robot.depth ? @robot.width : @robot.depth,
|
||||
1 - fraction,
|
||||
360,
|
||||
1,
|
||||
TAC::Palette::TIMECRAFTERS_TERTIARY,
|
||||
@robot.z
|
||||
)
|
||||
|
||||
@complete = fraction >= 1
|
||||
end
|
||||
|
||||
def update(dt)
|
||||
@accumulator += dt
|
||||
end
|
||||
end
|
||||
|
||||
class Comment < State
|
||||
def initialize(robot:, comment:)
|
||||
@robot = robot
|
||||
@comment = comment
|
||||
end
|
||||
|
||||
def start
|
||||
@robot.comment = @comment
|
||||
@complete = true
|
||||
end
|
||||
|
||||
def draw
|
||||
end
|
||||
|
||||
def update(dt)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -8,7 +8,7 @@ module TAC
|
||||
@field_container = field_container
|
||||
|
||||
@robots = []
|
||||
@field = Field.new(simulation: self, season: :freight_frenzy, container: @field_container)
|
||||
@field = Field.new(simulation: self, season: :power_play, container: @field_container)
|
||||
@show_paths = false
|
||||
|
||||
@last_milliseconds = Gosu.milliseconds
|
||||
@@ -29,7 +29,7 @@ module TAC
|
||||
def update
|
||||
@accumulator += (Gosu.milliseconds - @last_milliseconds) / 1000.0
|
||||
|
||||
while(@accumulator > @simulation_step)
|
||||
while @accumulator > @simulation_step
|
||||
@field.update
|
||||
@robots.each { |robot| robot.update(@simulation_step) }
|
||||
|
||||
@@ -41,7 +41,7 @@ module TAC
|
||||
end
|
||||
|
||||
def create_robot(alliance:, width:, depth:)
|
||||
robot = Simulator::Robot.new(alliance: alliance, width: width, depth: depth)
|
||||
robot = Simulator::Robot.new(alliance: alliance, width: width, depth: depth, container: @field_container)
|
||||
@robots << robot
|
||||
|
||||
return robot
|
||||
|
||||
@@ -8,12 +8,12 @@ module TAC
|
||||
background [TAC::Palette::TIMECRAFTERS_PRIMARY, TAC::Palette::TIMECRAFTERS_SECONDARY, TAC::Palette::TIMECRAFTERS_TERTIARY, TAC::Palette::TIMECRAFTERS_PRIMARY]
|
||||
end
|
||||
|
||||
@title_font = CyberarmEngine::Text.new(TAC::NAME, z: 100, size: 72, border: true, border_size: 3, font: THEME[:Label][:font])
|
||||
@title_font = CyberarmEngine::Text.new(TAC::NAME, z: 100, size: 72, border: true, border_size: 2, border_color: 0xff_000000, font: THEME[:TextBlock][:font], static: true)
|
||||
@logo = Gosu::Image.new("#{TAC::ROOT_PATH}/media/logo.png")
|
||||
|
||||
@title_animator = CyberarmEngine::Animator.new(start_time: 0, duration: 750, from: 0.0, to: 1.0, tween: :swing_from_to)
|
||||
@logo_animator = CyberarmEngine::Animator.new(start_time: 750, duration: 1_000, from: 0.0, to: 1.0, tween: :swing_to)
|
||||
@transition_animator = CyberarmEngine::Animator.new(start_time: 2_250, duration: 750, from: 0, to: 255, tween: :ease_out)
|
||||
@title_animator = CyberarmEngine::Animator.new(start_time: Gosu.milliseconds + 0, duration: 750, from: 0.0, to: 1.0, tween: :swing_from_to)
|
||||
@logo_animator = CyberarmEngine::Animator.new(start_time: Gosu.milliseconds + 750, duration: 1_000, from: 0.0, to: 1.0, tween: :swing_to)
|
||||
@transition_animator = CyberarmEngine::Animator.new(start_time: Gosu.milliseconds + 2_250, duration: 750, from: 0, to: 255, tween: :ease_out)
|
||||
@transition_color = Gosu::Color.new(0x00_111111)
|
||||
|
||||
@next_state = Editor
|
||||
@@ -30,15 +30,20 @@ module TAC
|
||||
def update
|
||||
super
|
||||
|
||||
request_repaint
|
||||
|
||||
@title_font.x = window.width / 2 - @title_font.width / 2
|
||||
@title_font.y = (window.height / 2 - (@logo.height / 2 + @title_font.height)) * @title_animator.transition
|
||||
|
||||
@transition_color.alpha = @transition_animator.transition
|
||||
|
||||
push_state(@next_state) if @transition_color.alpha >= 255
|
||||
if @transition_color.alpha >= 255
|
||||
pop_state
|
||||
push_state(@next_state)
|
||||
end
|
||||
end
|
||||
|
||||
def button_up(id)
|
||||
def button_down(id)
|
||||
super
|
||||
|
||||
push_state(@next_state)
|
||||
|
||||
@@ -8,6 +8,8 @@ class Editor < CyberarmEngine::GuiState
|
||||
@window_width = 0
|
||||
@window_height = 0
|
||||
|
||||
@last_tacnet_status = nil
|
||||
|
||||
@pages = {}
|
||||
@page = nil
|
||||
|
||||
@@ -34,9 +36,9 @@ class Editor < CyberarmEngine::GuiState
|
||||
@header_bar = flow(width: 1.0, height: 36) do
|
||||
background 0xff_006000
|
||||
|
||||
@header_bar_label = label TAC::NAME, width: 1.0, text_align: :center, text_size: 32
|
||||
@header_bar_label = label TAC::NAME, fill: true, text_align: :center, text_size: 32, font: TAC::THEME_BOLD_FONT, margin_left: BORDERLESS ? 36 * 3 : 0
|
||||
|
||||
@window_controls = flow(x: window.width - 36 * 2, y: 0, height: 1.0) do
|
||||
@window_controls = flow(width: 36 * 3, height: 1.0) do
|
||||
button get_image("#{TAC::ROOT_PATH}/media/icons/minus.png"), tip: "Minimize", image_height: 1.0 do
|
||||
window.minimize if window.respond_to?(:minimize)
|
||||
end
|
||||
@@ -128,9 +130,9 @@ class Editor < CyberarmEngine::GuiState
|
||||
end
|
||||
|
||||
def draw
|
||||
super
|
||||
@page&.draw
|
||||
|
||||
@page.draw if @page
|
||||
super
|
||||
end
|
||||
|
||||
def update
|
||||
@@ -138,15 +140,35 @@ class Editor < CyberarmEngine::GuiState
|
||||
|
||||
@page.update if @page
|
||||
|
||||
case window.backend.tacnet.status
|
||||
when :not_connected
|
||||
@tacnet_button.style.color = Gosu::Color::WHITE
|
||||
when :connecting
|
||||
@tacnet_button.style.color = TAC::Palette::TACNET_CONNECTING
|
||||
when :connected
|
||||
@tacnet_button.style.color = TAC::Palette::TACNET_CONNECTED
|
||||
when :connection_error
|
||||
@tacnet_button.style.color = TAC::Palette::TACNET_CONNECTION_ERROR
|
||||
if @last_tacnet_status != window.backend.tacnet.status
|
||||
@last_tacnet_status = window.backend.tacnet.status
|
||||
|
||||
case window.backend.tacnet.status
|
||||
when :not_connected
|
||||
@tacnet_button.style.color = Gosu::Color::WHITE
|
||||
@header_bar.style.background = 0xff_006000
|
||||
when :connected
|
||||
@tacnet_button.style.color = Gosu::Color::WHITE
|
||||
@header_bar.style.background = TAC::Palette::TACNET_PRIMARY
|
||||
when :connecting
|
||||
@tacnet_button.style.color = TAC::Palette::TACNET_CONNECTING
|
||||
@header_bar.style.background = TAC::Palette::TACNET_CONNECTING
|
||||
when :connection_error
|
||||
@tacnet_button.style.color = TAC::Palette::TACNET_CONNECTION_ERROR
|
||||
@header_bar.style.background = TAC::Palette::TACNET_CONNECTION_ERROR
|
||||
|
||||
unless @page.is_a?(TAC::Pages::TACNET)
|
||||
push_state(TAC::Dialog::TACNETDialog, title: "TACNET Connection Error", message: window.backend.tacnet.full_status)
|
||||
end
|
||||
end
|
||||
|
||||
@tacnet_button.style.default[:color] = @tacnet_button.style.color
|
||||
@header_bar.style.default[:background] = @header_bar.style.background
|
||||
|
||||
@tacnet_button.recalculate
|
||||
@header_bar.recalculate
|
||||
|
||||
request_repaint
|
||||
end
|
||||
|
||||
window.width = Gosu.available_width / 2 if window.width < Gosu.available_width / 2
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module TAC
|
||||
class TACNET
|
||||
DEFAULT_HOSTNAME = "192.168.49.1"
|
||||
DEFAULT_HOSTNAME = "192.168.49.1".freeze
|
||||
DEFAULT_PORT = 8962
|
||||
|
||||
SYNC_INTERVAL = 250 # ms
|
||||
@@ -30,7 +30,7 @@ module TAC
|
||||
end
|
||||
|
||||
def full_status
|
||||
_status = status.to_s.split("_").map { |c| c.capitalize }.join(" ")
|
||||
_status = status.to_s.split("_").map(&:capitalize).join(" ")
|
||||
|
||||
if connected?
|
||||
net_stats = ""
|
||||
@@ -42,7 +42,7 @@ module TAC
|
||||
|
||||
"<b>Status:</b> #{_status}\n\n#{net_stats}"
|
||||
elsif @connection&.client && @connection.client.socket_error?
|
||||
"<b>Status:</b> #{_status}\n\n#{@connection.client.last_socket_error.to_s}"
|
||||
"<b>Status:</b> #{_status}\n\n#{@connection.client.last_socket_error}"
|
||||
else
|
||||
"<b>Status:</b> #{_status}"
|
||||
end
|
||||
@@ -53,10 +53,10 @@ module TAC
|
||||
end
|
||||
|
||||
def close
|
||||
if connected?
|
||||
@connection.close
|
||||
@connection = nil
|
||||
end
|
||||
return unless connected?
|
||||
|
||||
@connection.close
|
||||
@connection = nil
|
||||
end
|
||||
|
||||
def client
|
||||
|
||||
@@ -8,7 +8,9 @@ module TAC
|
||||
attr_reader :uuid, :read_queue, :write_queue, :socket,
|
||||
:packets_sent, :packets_received,
|
||||
:data_sent, :data_received
|
||||
|
||||
attr_accessor :sync_interval, :last_socket_error, :socket_error
|
||||
|
||||
def initialize
|
||||
@uuid = SecureRandom.uuid
|
||||
@read_queue = []
|
||||
@@ -20,8 +22,11 @@ module TAC
|
||||
@socket_error = false
|
||||
@bound = false
|
||||
|
||||
@packets_sent, @packets_received = 0, 0
|
||||
@data_sent, @data_received = 0, 0
|
||||
@packets_sent = 0
|
||||
@packets_received = 0
|
||||
|
||||
@data_sent = 0
|
||||
@data_received = 0
|
||||
end
|
||||
|
||||
def uuid=(id)
|
||||
@@ -39,17 +44,15 @@ module TAC
|
||||
Thread.new do
|
||||
while connected?
|
||||
# Read from socket
|
||||
while message_in = read
|
||||
if message_in.empty?
|
||||
break
|
||||
else
|
||||
log.i(TAG, "Read: " + message_in)
|
||||
while (message_in = read)
|
||||
break if message_in.empty?
|
||||
|
||||
@read_queue << message_in
|
||||
log.i(TAG, "Read: #{message_in}")
|
||||
|
||||
@packets_received += 1
|
||||
@data_received += message_in.length
|
||||
end
|
||||
@read_queue << message_in
|
||||
|
||||
@packets_received += 1
|
||||
@data_received += message_in.length
|
||||
end
|
||||
|
||||
sleep @sync_interval / 1000.0
|
||||
@@ -59,12 +62,12 @@ module TAC
|
||||
Thread.new do
|
||||
while connected?
|
||||
# Write to socket
|
||||
while message_out = @write_queue.shift
|
||||
while (message_out = @write_queue.shift)
|
||||
write(message_out)
|
||||
|
||||
@packets_sent += 1
|
||||
@data_sent += message_out.to_s.length
|
||||
log.i(TAG, "Write: " + message_out.to_s)
|
||||
log.i(TAG, "Write: #{message_out}")
|
||||
end
|
||||
|
||||
sleep @sync_interval / 1000.0
|
||||
@@ -82,7 +85,7 @@ module TAC
|
||||
while message
|
||||
puts(message)
|
||||
|
||||
log.i(TAG, "Writing to Queue: " + message)
|
||||
log.i(TAG, "Writing to Queue: #{message}")
|
||||
|
||||
message = gets
|
||||
end
|
||||
@@ -101,32 +104,29 @@ module TAC
|
||||
end
|
||||
|
||||
def closed?
|
||||
@socket.closed? if @socket
|
||||
@socket&.closed?
|
||||
end
|
||||
|
||||
def write(message)
|
||||
begin
|
||||
@socket.puts("#{message}#{PACKET_TAIL}")
|
||||
rescue => error
|
||||
@last_socket_error = error
|
||||
@socket_error = true
|
||||
log.e(TAG, error.message)
|
||||
close
|
||||
end
|
||||
@socket.puts("#{message}#{PACKET_TAIL}") if connected?
|
||||
rescue => error
|
||||
@last_socket_error = error
|
||||
@socket_error = true
|
||||
|
||||
log.e(TAG, error.message)
|
||||
|
||||
close
|
||||
end
|
||||
|
||||
def read
|
||||
begin
|
||||
message = @socket.gets
|
||||
rescue => error
|
||||
@last_socket_error = error
|
||||
@socket_error = true
|
||||
@socket&.gets&.strip if connected?
|
||||
rescue => error
|
||||
@last_socket_error = error
|
||||
@socket_error = true
|
||||
|
||||
message = ""
|
||||
end
|
||||
log.e(TAG, error.message)
|
||||
|
||||
|
||||
return message.strip
|
||||
close
|
||||
end
|
||||
|
||||
def puts(message)
|
||||
@@ -138,11 +138,11 @@ module TAC
|
||||
end
|
||||
|
||||
def encode(message)
|
||||
return message
|
||||
message
|
||||
end
|
||||
|
||||
def decode(blob)
|
||||
return blob
|
||||
blob
|
||||
end
|
||||
|
||||
def flush
|
||||
@@ -151,7 +151,8 @@ module TAC
|
||||
|
||||
def close(reason = nil)
|
||||
write(reason) if reason
|
||||
@socket.close if @socket
|
||||
|
||||
@socket&.close
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -47,7 +47,7 @@ module TAC
|
||||
|
||||
def handle_handshake(packet)
|
||||
if @host_is_a_connection
|
||||
$window.backend.tacnet.client.uuid = packet.body
|
||||
CyberarmEngine::Window.instance.backend.tacnet.client.uuid = packet.body
|
||||
end
|
||||
end
|
||||
|
||||
@@ -59,7 +59,7 @@ module TAC
|
||||
def handle_error(packet)
|
||||
if @host_is_a_connection
|
||||
title, message = packet.body.split(Packet::PROTOCOL_SEPERATOR, 2)
|
||||
$window.push_state(TAC::Dialog::TACNETDialog, title: title, message: message)
|
||||
CyberarmEngine::Window.instance.push_state(TAC::Dialog::TACNETDialog, title: title, message: message)
|
||||
else
|
||||
log.e(TAG, "Remote error: #{title}: #{message}")
|
||||
end
|
||||
@@ -73,11 +73,11 @@ module TAC
|
||||
if data.is_a?(Hash) && data.dig(:config, :spec_version) == TAC::CONFIG_SPEC_VERSION
|
||||
File.open("#{TAC::CONFIGS_PATH}/#{config_name}.json", "w") { |f| f.write json }
|
||||
|
||||
if $window.backend.config&.name == config_name
|
||||
$window.backend.load_config(config_name)
|
||||
if CyberarmEngine::Window.instance.backend.config&.name == config_name
|
||||
CyberarmEngine::Window.instance.backend.load_config(config_name)
|
||||
end
|
||||
else
|
||||
$window.push_state(TAC::Dialog::AlertDialog, title: "Invalid Config", message: "Supported config spec: v#{TAC::CONFIG_SPEC_VERSION} got v#{data.dig(:config, :spec_version)}")
|
||||
CyberarmEngine::Window.instance.push_state(TAC::Dialog::AlertDialog, title: "Invalid Config", message: "Supported config spec: v#{TAC::CONFIG_SPEC_VERSION} got v#{data.dig(:config, :spec_version)}")
|
||||
end
|
||||
|
||||
rescue JSON::ParserError => e
|
||||
@@ -97,7 +97,7 @@ module TAC
|
||||
end
|
||||
|
||||
if @host_is_a_connection
|
||||
$window.backend.tacnet.puts(pkt)
|
||||
CyberarmEngine::Window.instance.backend.tacnet.puts(pkt)
|
||||
else
|
||||
$server.active_client.puts(pkt)
|
||||
end
|
||||
@@ -119,20 +119,20 @@ module TAC
|
||||
config = Config.new(name)
|
||||
|
||||
if config.configuration.revision < revision
|
||||
$window.backend.tacnet.puts( PacketHandler.packet_download_config(name) )
|
||||
CyberarmEngine::Window.instance.backend.tacnet.puts( PacketHandler.packet_download_config(name) )
|
||||
elsif config.configuration.revision > revision
|
||||
$window.backend.tacnet.puts( PacketHandler.packet_upload_config(name, JSON.dump( config )) )
|
||||
CyberarmEngine::Window.instance.backend.tacnet.puts( PacketHandler.packet_upload_config(name, JSON.dump( config )) )
|
||||
end
|
||||
|
||||
else
|
||||
$window.backend.tacnet.puts( PacketHandler.packet_download_config(name) )
|
||||
CyberarmEngine::Window.instance.backend.tacnet.puts( PacketHandler.packet_download_config(name) )
|
||||
end
|
||||
end
|
||||
|
||||
_diff.each do |name|
|
||||
config = Config.new(name)
|
||||
|
||||
$window.backend.tacnet.puts( PacketHandler.packet_upload_config(name, JSON.dump( config )) )
|
||||
CyberarmEngine::Window.instance.backend.tacnet.puts( PacketHandler.packet_upload_config(name, JSON.dump( config )) )
|
||||
end
|
||||
else
|
||||
if $server.active_client && $server.active_client.connected?
|
||||
@@ -144,43 +144,43 @@ module TAC
|
||||
def handle_select_config(packet)
|
||||
config_name = packet.body
|
||||
|
||||
$window.backend.settings.config = config_name
|
||||
$window.backend.save_settings
|
||||
$window.backend.load_config(config_name)
|
||||
CyberarmEngine::Window.instance.backend.settings.config = config_name
|
||||
CyberarmEngine::Window.instance.backend.save_settings
|
||||
CyberarmEngine::Window.instance.backend.load_config(config_name)
|
||||
end
|
||||
|
||||
def handle_add_config(packet)
|
||||
config_name = packet.body
|
||||
|
||||
if $window.backend.configs_list.include?(config_name)
|
||||
if CyberarmEngine::Window.instance.backend.configs_list.include?(config_name)
|
||||
unless @host_is_a_connection
|
||||
if $server.active_client&.connected?
|
||||
$server.active_client.puts(PacketHandler.packet_error("Config already exists!", "A config with the name #{config_name} already exists over here."))
|
||||
end
|
||||
end
|
||||
else
|
||||
$window.backend.write_new_config(config_name)
|
||||
CyberarmEngine::Window.instance.backend.write_new_config(config_name)
|
||||
end
|
||||
end
|
||||
|
||||
def handle_update_config(packet)
|
||||
old_config_name, new_config_name = packet.body.split(PROTOCOL_SEPERATOR, 2)
|
||||
|
||||
if $window.backend.configs_list.include?(config_name)
|
||||
if CyberarmEngine::Window.instance.backend.configs_list.include?(config_name)
|
||||
unless @host_is_a_connection
|
||||
if $server.active_client&.connected?
|
||||
$server.active_client.puts(PacketHandler.packet_error("Config already exists!", "A config with the name #{config_name} already exists over here."))
|
||||
end
|
||||
end
|
||||
else
|
||||
$window.backend.move_config(old_config_name, new_config_name)
|
||||
CyberarmEngine::Window.instance.backend.move_config(old_config_name, new_config_name)
|
||||
end
|
||||
end
|
||||
|
||||
def handle_delete_config(packet)
|
||||
config_name = packet.body
|
||||
|
||||
$window.backend.delete_config(config_name)
|
||||
CyberarmEngine::Window.instance.backend.delete_config(config_name)
|
||||
end
|
||||
|
||||
def self.packet_handshake(client_uuid)
|
||||
|
||||
13
lib/theme.rb
13
lib/theme.rb
@@ -1,12 +1,15 @@
|
||||
module TAC
|
||||
THEME_FONT = "#{TAC::ROOT_PATH}/media/fonts/DejaVuSansCondensed.ttf"
|
||||
THEME_FONT = "#{TAC::ROOT_PATH}/media/fonts/NotoSans-Bold.ttf"
|
||||
THEME_BOLD_FONT = "#{TAC::ROOT_PATH}/media/fonts/NotoSans-Black.ttf"
|
||||
THEME = {
|
||||
Label: {
|
||||
TextBlock: {
|
||||
text_static: true,
|
||||
font: THEME_FONT,
|
||||
text_size: 22,
|
||||
color: Gosu::Color.new(0xee_ffffff),
|
||||
},
|
||||
Button: {
|
||||
font: THEME_BOLD_FONT,
|
||||
text_size: 22,
|
||||
background: TAC::Palette::TIMECRAFTERS_PRIMARY,
|
||||
border_thickness: 1,
|
||||
@@ -20,6 +23,7 @@ module TAC
|
||||
},
|
||||
EditLine: {
|
||||
caret_color: Gosu::Color.new(0xff_88ef90),
|
||||
font: THEME_FONT
|
||||
},
|
||||
ToggleButton: {
|
||||
width: 18,
|
||||
@@ -31,10 +35,10 @@ module TAC
|
||||
color: Gosu::Color.new(0xff_ffffff),
|
||||
background: Gosu::Color.new(0xff_800000),
|
||||
hover: {
|
||||
background: Gosu::Color.new(0xff_600000),
|
||||
background: Gosu::Color.new(0xff_c00000),
|
||||
},
|
||||
active: {
|
||||
background: Gosu::Color.new(0xff_c00000),
|
||||
background: Gosu::Color.new(0xff_600000),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +53,7 @@ module TAC
|
||||
padding_top: THEME_ITEM_PADDING,
|
||||
padding_bottom: THEME_ITEM_PADDING
|
||||
}
|
||||
THEME_HIGHLIGHTED_COLOR = Gosu::Color.rgb(255, 175, 0) # Gosu::Color.new(0xff_f080f0)
|
||||
THEME_EVEN_COLOR = Gosu::Color.new(0xff_202020)
|
||||
THEME_ODD_COLOR = Gosu::Color.new(0xff_606060)
|
||||
THEME_CONTENT_BACKGROUND = Gosu::Color.new(0x88_007f3f)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
module TAC
|
||||
NAME = "TimeCrafters Configuration Tool"
|
||||
VERSION = "0.5.1"
|
||||
VERSION = "0.6.0"
|
||||
RELEASE_NAME = "Beta"
|
||||
end
|
||||
@@ -11,6 +11,8 @@ module TAC
|
||||
|
||||
if ARGV.join.include?("--game-clock-remote-display")
|
||||
push_state(PracticeGameClock::View, remote_control_mode: true)
|
||||
elsif ARGV.join.include?("--intro")
|
||||
push_state(CyberarmEngine::IntroState, forward: TAC::States::Boot)
|
||||
else
|
||||
push_state(TAC::States::Boot)
|
||||
end
|
||||
@@ -29,6 +31,10 @@ module TAC
|
||||
@notification_manager.update
|
||||
end
|
||||
|
||||
def needs_redraw?
|
||||
states.any?(&:needs_repaint?) || @notification_manager.instance_variable_get(:@drivers).size.positive?
|
||||
end
|
||||
|
||||
def toast(title, message = nil)
|
||||
@notification_manager.create_notification(
|
||||
priority: GosuNotifications::Notification::PRIORITY_HIGH,
|
||||
|
||||
@@ -1,187 +0,0 @@
|
||||
Fonts are (c) Bitstream (see below). DejaVu changes are in public domain.
|
||||
Glyphs imported from Arev fonts are (c) Tavmjong Bah (see below)
|
||||
|
||||
|
||||
Bitstream Vera Fonts Copyright
|
||||
------------------------------
|
||||
|
||||
Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is
|
||||
a trademark of Bitstream, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of the fonts accompanying this license ("Fonts") and associated
|
||||
documentation files (the "Font Software"), to reproduce and distribute the
|
||||
Font Software, including without limitation the rights to use, copy, merge,
|
||||
publish, distribute, and/or sell copies of the Font Software, and to permit
|
||||
persons to whom the Font Software is furnished to do so, subject to the
|
||||
following conditions:
|
||||
|
||||
The above copyright and trademark notices and this permission notice shall
|
||||
be included in all copies of one or more of the Font Software typefaces.
|
||||
|
||||
The Font Software may be modified, altered, or added to, and in particular
|
||||
the designs of glyphs or characters in the Fonts may be modified and
|
||||
additional glyphs or characters may be added to the Fonts, only if the fonts
|
||||
are renamed to names not containing either the words "Bitstream" or the word
|
||||
"Vera".
|
||||
|
||||
This License becomes null and void to the extent applicable to Fonts or Font
|
||||
Software that has been modified and is distributed under the "Bitstream
|
||||
Vera" names.
|
||||
|
||||
The Font Software may be sold as part of a larger software package but no
|
||||
copy of one or more of the Font Software typefaces may be sold by itself.
|
||||
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT,
|
||||
TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME
|
||||
FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING
|
||||
ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE
|
||||
FONT SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the names of Gnome, the Gnome
|
||||
Foundation, and Bitstream Inc., shall not be used in advertising or
|
||||
otherwise to promote the sale, use or other dealings in this Font Software
|
||||
without prior written authorization from the Gnome Foundation or Bitstream
|
||||
Inc., respectively. For further information, contact: fonts at gnome dot
|
||||
org.
|
||||
|
||||
Arev Fonts Copyright
|
||||
------------------------------
|
||||
|
||||
Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the fonts accompanying this license ("Fonts") and
|
||||
associated documentation files (the "Font Software"), to reproduce
|
||||
and distribute the modifications to the Bitstream Vera Font Software,
|
||||
including without limitation the rights to use, copy, merge, publish,
|
||||
distribute, and/or sell copies of the Font Software, and to permit
|
||||
persons to whom the Font Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright and trademark notices and this permission notice
|
||||
shall be included in all copies of one or more of the Font Software
|
||||
typefaces.
|
||||
|
||||
The Font Software may be modified, altered, or added to, and in
|
||||
particular the designs of glyphs or characters in the Fonts may be
|
||||
modified and additional glyphs or characters may be added to the
|
||||
Fonts, only if the fonts are renamed to names not containing either
|
||||
the words "Tavmjong Bah" or the word "Arev".
|
||||
|
||||
This License becomes null and void to the extent applicable to Fonts
|
||||
or Font Software that has been modified and is distributed under the
|
||||
"Tavmjong Bah Arev" names.
|
||||
|
||||
The Font Software may be sold as part of a larger software package but
|
||||
no copy of one or more of the Font Software typefaces may be sold by
|
||||
itself.
|
||||
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL
|
||||
TAVMJONG BAH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Tavmjong Bah shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other
|
||||
dealings in this Font Software without prior written authorization
|
||||
from Tavmjong Bah. For further information, contact: tavmjong @ free
|
||||
. fr.
|
||||
|
||||
TeX Gyre DJV Math
|
||||
-----------------
|
||||
Fonts are (c) Bitstream (see below). DejaVu changes are in public domain.
|
||||
|
||||
Math extensions done by B. Jackowski, P. Strzelczyk and P. Pianowski
|
||||
(on behalf of TeX users groups) are in public domain.
|
||||
|
||||
Letters imported from Euler Fraktur from AMSfonts are (c) American
|
||||
Mathematical Society (see below).
|
||||
Bitstream Vera Fonts Copyright
|
||||
Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera
|
||||
is a trademark of Bitstream, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of the fonts accompanying this license (“Fonts”) and associated
|
||||
documentation
|
||||
files (the “Font Software”), to reproduce and distribute the Font Software,
|
||||
including without limitation the rights to use, copy, merge, publish,
|
||||
distribute,
|
||||
and/or sell copies of the Font Software, and to permit persons to whom
|
||||
the Font Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright and trademark notices and this permission notice
|
||||
shall be
|
||||
included in all copies of one or more of the Font Software typefaces.
|
||||
|
||||
The Font Software may be modified, altered, or added to, and in particular
|
||||
the designs of glyphs or characters in the Fonts may be modified and
|
||||
additional
|
||||
glyphs or characters may be added to the Fonts, only if the fonts are
|
||||
renamed
|
||||
to names not containing either the words “Bitstream” or the word “Vera”.
|
||||
|
||||
This License becomes null and void to the extent applicable to Fonts or
|
||||
Font Software
|
||||
that has been modified and is distributed under the “Bitstream Vera”
|
||||
names.
|
||||
|
||||
The Font Software may be sold as part of a larger software package but
|
||||
no copy
|
||||
of one or more of the Font Software typefaces may be sold by itself.
|
||||
|
||||
THE FONT SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT,
|
||||
TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME
|
||||
FOUNDATION
|
||||
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL,
|
||||
SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN
|
||||
ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR
|
||||
INABILITY TO USE
|
||||
THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
Except as contained in this notice, the names of GNOME, the GNOME
|
||||
Foundation,
|
||||
and Bitstream Inc., shall not be used in advertising or otherwise to promote
|
||||
the sale, use or other dealings in this Font Software without prior written
|
||||
authorization from the GNOME Foundation or Bitstream Inc., respectively.
|
||||
For further information, contact: fonts at gnome dot org.
|
||||
|
||||
AMSFonts (v. 2.2) copyright
|
||||
|
||||
The PostScript Type 1 implementation of the AMSFonts produced by and
|
||||
previously distributed by Blue Sky Research and Y&Y, Inc. are now freely
|
||||
available for general use. This has been accomplished through the
|
||||
cooperation
|
||||
of a consortium of scientific publishers with Blue Sky Research and Y&Y.
|
||||
Members of this consortium include:
|
||||
|
||||
Elsevier Science IBM Corporation Society for Industrial and Applied
|
||||
Mathematics (SIAM) Springer-Verlag American Mathematical Society (AMS)
|
||||
|
||||
In order to assure the authenticity of these fonts, copyright will be
|
||||
held by
|
||||
the American Mathematical Society. This is not meant to restrict in any way
|
||||
the legitimate use of the fonts, such as (but not limited to) electronic
|
||||
distribution of documents containing these fonts, inclusion of these fonts
|
||||
into other public domain or commercial font collections or computer
|
||||
applications, use of the outline data to create derivative fonts and/or
|
||||
faces, etc. However, the AMS does require that the AMS copyright notice be
|
||||
removed from any derivative versions of the fonts which have been altered in
|
||||
any way. In addition, to ensure the fidelity of TeX documents using Computer
|
||||
Modern fonts, Professor Donald Knuth, creator of the Computer Modern faces,
|
||||
has requested that any alterations which yield different font metrics be
|
||||
given a different name.
|
||||
|
||||
$Id$
|
||||
Binary file not shown.
BIN
media/fonts/NotoSans-Black.ttf
Normal file
BIN
media/fonts/NotoSans-Black.ttf
Normal file
Binary file not shown.
BIN
media/fonts/NotoSans-Bold.ttf
Normal file
BIN
media/fonts/NotoSans-Bold.ttf
Normal file
Binary file not shown.
BIN
media/fonts/NotoSans-Medium.ttf
Normal file
BIN
media/fonts/NotoSans-Medium.ttf
Normal file
Binary file not shown.
BIN
media/fonts/NotoSans-Regular.ttf
Normal file
BIN
media/fonts/NotoSans-Regular.ttf
Normal file
Binary file not shown.
93
media/fonts/OFL.txt
Normal file
93
media/fonts/OFL.txt
Normal file
@@ -0,0 +1,93 @@
|
||||
Copyright 2015-2021 Google LLC. All Rights Reserved.
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
BIN
media/screenshots/screenshot_editor.png
Normal file
BIN
media/screenshots/screenshot_editor.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 280 KiB |
Reference in New Issue
Block a user