smash_and_grab 0.0.3alpha → 0.0.5alpha

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. data/Gemfile.lock +1 -1
  2. data/README.md +31 -16
  3. data/config/gui/schema.yml +3 -2
  4. data/config/map/entities.yml +36 -12
  5. data/lib/smash_and_grab/abilities/ability.rb +5 -0
  6. data/lib/smash_and_grab/abilities/melee.rb +11 -5
  7. data/lib/smash_and_grab/abilities/ranged.rb +20 -0
  8. data/lib/smash_and_grab/abilities/sprint.rb +4 -0
  9. data/lib/smash_and_grab/abilities.rb +3 -1
  10. data/lib/smash_and_grab/fidgit_ext/event.rb +77 -0
  11. data/lib/smash_and_grab/gui/editor_selector.rb +54 -73
  12. data/lib/smash_and_grab/gui/entity_panel.rb +110 -0
  13. data/lib/smash_and_grab/gui/entity_summary.rb +9 -8
  14. data/lib/smash_and_grab/gui/game_log.rb +44 -0
  15. data/lib/smash_and_grab/gui/info_panel.rb +39 -95
  16. data/lib/smash_and_grab/gui/object_panel.rb +37 -0
  17. data/lib/smash_and_grab/gui/scenario_panel.rb +21 -0
  18. data/lib/smash_and_grab/history/editor_actions/place_object.rb +1 -1
  19. data/lib/smash_and_grab/main.rb +11 -16
  20. data/lib/smash_and_grab/map/map.rb +1 -0
  21. data/lib/smash_and_grab/map/tile.rb +6 -3
  22. data/lib/smash_and_grab/map/wall.rb +4 -2
  23. data/lib/smash_and_grab/mouse_selection.rb +103 -46
  24. data/lib/smash_and_grab/objects/entity.rb +219 -30
  25. data/lib/smash_and_grab/objects/static.rb +7 -5
  26. data/lib/smash_and_grab/objects/vehicle.rb +7 -5
  27. data/lib/smash_and_grab/objects/world_object.rb +13 -3
  28. data/lib/smash_and_grab/path.rb +13 -7
  29. data/lib/smash_and_grab/players/player.rb +15 -10
  30. data/lib/smash_and_grab/states/edit_level.rb +17 -0
  31. data/lib/smash_and_grab/states/play_level.rb +20 -10
  32. data/lib/smash_and_grab/version.rb +1 -1
  33. data/lib/smash_and_grab.rb +18 -14
  34. data/test/smash_and_grab/abilities/melee_test.rb +37 -39
  35. data/test/teststrap.rb +3 -3
  36. metadata +21 -16
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- smash_and_grab (0.0.3alpha)
4
+ smash_and_grab (0.0.5alpha)
5
5
  chingu (~> 0.9rc7)
6
6
  fidgit (~> 0.1.10)
7
7
  gosu (~> 0.7.41)
data/README.md CHANGED
@@ -7,29 +7,29 @@ Smash and Grab
7
7
  Description
8
8
  -----------
9
9
 
10
- _Smash and Grab!_ is a retro isometric supervillainous turn-based hiest game.
10
+ _Smash and Grab!_ is a retro isometric, super-villainous, turn-based heist game.
11
11
 
12
12
  Requirements
13
13
  ------------
14
14
 
15
15
  ### Windows
16
16
 
17
- If running <tt>smash_and_grab.exe</tt>, there are no other requirements.
17
+ If running `smash_and_grab.exe`, there are no other requirements.
18
18
 
19
19
  ### OS X
20
20
 
21
- If running OS X, use the executable (<tt>SmashAndGrab.app</tt>), which has no dependencies.
21
+ If running OS X, use the executable (`SmashAndGrab.app`), which has no dependencies.
22
22
 
23
23
  ### Source for Linux (or Windows/OS X if not using the executable)
24
24
 
25
- If running from source, users must install the Ruby interpreter and some rubygems. Linux users must also install some "extra dependencies](https://github.com/jlnr/gosu/wiki/Getting-Started-on-Linux for Gosu.
25
+ If running from source, users must install the Ruby interpreter and some rubygems. Linux users must also install some [extra dependencies](https://github.com/jlnr/gosu/wiki/Getting-Started-on-Linux) for Gosu.
26
26
 
27
27
  #### Dependencies
28
28
 
29
29
  * Ruby 1.9.2 (Install via package manager or rvm). Ruby 1.9.3 recommended though, since loading is significantly faster.
30
- ** Gosu gem 0.7.32 (Dependencies: "Linux only](https://github.com/jlnr/gosu/wiki/Getting-Started-on-Linux)
31
- ** A number of other rubygems, which can be installed automatically using Bundler (see below).
32
- ** Linux Only: <tt>xsel</tt> or <tt>xcopy</tt> command to allow access to the system clipboard:
30
+ * Gosu gem 0.7.32 - Dependencies: [Linux only](https://github.com/jlnr/gosu/wiki/Getting-Started-on-Linux)
31
+ * A number of other rubygems, which can be installed automatically using Bundler (see below).
32
+ * Linux Only: <tt>xsel</tt> or <tt>xcopy</tt> command to allow access to the system clipboard:
33
33
  <pre> sudo apt-get install xsel</pre>
34
34
 
35
35
  #### Using Bundler to install gems
@@ -61,22 +61,37 @@ Move your supervillains around until you win!
61
61
 
62
62
  ### Implemented game features
63
63
 
64
+ * Your Villains can:
65
+ - move around.
66
+ - melee with enemies (Goodies or Bystanders).
67
+ - sprint to get extra movement (sacrificing all actions for that turn).
68
+ - get reactive melee attacks from ZoC.
69
+
70
+ * Zones of Control:
71
+ - Enemies project a ZoC into adjacent tiles IF they have enough actions left to melee.
72
+ - Entering or leaving a ZoC triggers a melee attack, which will occur before the mover can attack!
73
+
74
+ * Goodies will:
75
+ - attack if they can or wander aimlessly in their turn.
76
+ - Get reactive melee attacks from ZoC.
77
+
78
+ * Bystanders will wander aimlessly in their turn.
79
+
64
80
  * Scroll map with keyboard arrows; zoom with mouse wheel.
65
- * Your Villains can move around.
66
- * Your Villains can melee with enemies (Goodies or Bystanders).
67
- * You can activate _Sprint_ ability to give a Villain extra movement (sacrificing all actions for that turn).
68
- * Goodies and Bystanders will take a turn (very trivial AI) when you end yours.
69
- * Editor works, but some bugs with placing Vehicles over other objects.
70
81
  * Saving/loading (F5/F6) of state in Editor & Game.
71
82
  * Undo/Redo (Ctrl-Z/Ctrl-Shift-Z)support in both Editor and Game (can't take back attacks though, since they are non-deterministic).
72
83
 
84
+ ### Implemented editor features
85
+
86
+ * Editor works, but some bugs with placing Vehicles where there are existing objects.
87
+
73
88
  ### Saved data
74
89
 
75
90
  Save games and configuration are saved into (Windows):
76
91
 
77
92
  C:\Users\<your-username>\AppData\Roaming\Smash And Grab\
78
93
 
79
- or (OS X / Linux)
94
+ or (OS X / Linux):
80
95
 
81
96
  /home/<your-username>/.smash_and_grab/
82
97
 
@@ -91,12 +106,12 @@ Many thanks to:
91
106
  Third party tools and assets used
92
107
  ---------------------------------
93
108
 
94
- * Original music by [Maverick (Brian Peppers)](http://polyhedricpeppers.weebly.com/). [![http://i.creativecommons.org/l/by-sa/3.0/88x31.png](CC BY-SA)](http://creativecommons.org/licenses/by-sa/3.0/)
109
+ * Original music by [Maverick (Brian Peppers)](http://polyhedricpeppers.weebly.com/). [![CC BY-SA](http://i.creativecommons.org/l/by-sa/3.0/88x31.png)](http://creativecommons.org/licenses/by-sa/3.0/)
95
110
  * Original sprites created with [GIMP](http://www.gimp.org/) and Graphics Gale [Free Edition]
96
- * Sound effects created using [bfxr](http://www.bfxr.net/) and converted using [Audacity](http://audacity.sourceforge.net/
111
+ * Sound effects created using [bfxr](http://www.bfxr.net/) and converted using [Audacity](http://audacity.sourceforge.net/)
97
112
  * [Unmasked font](http://www.blambot.com/font_unmasked.shtml) by "Nate Piekos" [Free for personal use]
98
113
  * [Gosu](http://libgosu.org/) game development library
99
114
  * [Chingu](http://ippa.se/chingu) game library (extending Gosu)
100
115
  * [Fidgit](https://github.com/Spooner/fidgit) gui library (extending Chingu)
101
- * [Texplay](http://banisterfiend.wordpress.com/2008/08/23/texplay-an-image-manipulation-tool-for-ruby-and-gosu/ image manipulation library for Gosu.
116
+ * [Texplay](http://banisterfiend.wordpress.com/2008/08/23/texplay-an-image-manipulation-tool-for-ruby-and-gosu/) image manipulation library for Gosu.
102
117
  * [R18n](http://r18n.rubyforge.org/) i18n library
@@ -54,8 +54,9 @@
54
54
  :background_color: ?very_dark_blue
55
55
 
56
56
  :ScrollBar: # < Composite
57
- :rail_width: 20
57
+ :rail_width: 14
58
58
 
59
59
  :ScrollWindow: # < Composite
60
- :scroll_bar_thickness: 20
60
+ :scroll_bar_thickness: 14
61
+ :border_color: ?dark_blue
61
62
 
@@ -16,12 +16,12 @@
16
16
  :abilities:
17
17
  -
18
18
  :type: :melee
19
- :skill: 4
19
+ :skill: 3
20
20
  -
21
21
  :type: :ranged
22
- :skill: 1
23
- :range: 3
24
- :action_cost: 2
22
+ :skill: 2
23
+ :min_range: 2
24
+ :max_range: 5
25
25
  -
26
26
  :type: :sprint
27
27
  :skill: 4
@@ -56,12 +56,12 @@
56
56
  :faction: :baddies
57
57
  :spritesheet_position: [1, 4]
58
58
  :movement_points: 8
59
- :action_points: 3
59
+ :action_points: 2
60
60
  :health: 15
61
61
  :abilities:
62
62
  -
63
63
  :type: :melee
64
- :skill: 5
64
+ :skill: 4
65
65
  -
66
66
  :type: :sprint
67
67
  :skill: 1
@@ -70,13 +70,12 @@
70
70
  :faction: :baddies
71
71
  :spritesheet_position: [0, 4]
72
72
  :movement_points: 5
73
- :action_points: 3
73
+ :action_points: 1
74
74
  :health: 10
75
75
  :abilities:
76
76
  -
77
77
  :type: :melee
78
- :skill: 4
79
- :action_cost: 1
78
+ :skill: 5
80
79
  -
81
80
  :type: :sprint
82
81
  :skill: 1
@@ -99,7 +98,7 @@
99
98
  :faction: :baddies
100
99
  :spritesheet_position: [7, 4]
101
100
  :movement_points: 7
102
- :action_points: 1
101
+ :action_points: 2
103
102
  :health: 10
104
103
  :abilities:
105
104
  -
@@ -139,6 +138,11 @@
139
138
  -
140
139
  :type: :melee
141
140
  :skill: 1
141
+ -
142
+ :type: :ranged
143
+ :skill: 2
144
+ :min_range: 2
145
+ :max_range: 6
142
146
  -
143
147
  :type: :sprint
144
148
  :skill: 2
@@ -153,6 +157,11 @@
153
157
  -
154
158
  :type: :melee
155
159
  :skill: 2
160
+ -
161
+ :type: :ranged
162
+ :skill: 2
163
+ :min_range: 2
164
+ :max_range: 8
156
165
  -
157
166
  :type: :sprint
158
167
  :skill: 2
@@ -167,6 +176,11 @@
167
176
  -
168
177
  :type: :melee
169
178
  :skill: 2
179
+ -
180
+ :type: :ranged
181
+ :skill: 2
182
+ :min_range: 2
183
+ :max_range: 8
170
184
  -
171
185
  :type: :sprint
172
186
  :skill: 2
@@ -181,6 +195,11 @@
181
195
  -
182
196
  :type: :melee
183
197
  :skill: 1
198
+ -
199
+ :type: :ranged
200
+ :skill: 3
201
+ :min_range: 3
202
+ :max_range: 9
184
203
  -
185
204
  :type: :sprint
186
205
  :skill: 2
@@ -195,6 +214,11 @@
195
214
  -
196
215
  :type: :melee
197
216
  :skill: 1
217
+ -
218
+ :type: :ranged
219
+ :skill: 4
220
+ :min_range: 4
221
+ :max_range: 8
198
222
 
199
223
  # - Superheroes -
200
224
 
@@ -272,7 +296,7 @@
272
296
  :faction: :goodies
273
297
  :spritesheet_position: [3, 1]
274
298
  :movement_points: 8
275
- :action_points: 3
299
+ :action_points: 2
276
300
  :health: 15
277
301
  :abilities:
278
302
  -
@@ -305,7 +329,7 @@
305
329
  :abilities:
306
330
  -
307
331
  :type: :melee
308
- :skill: 5
332
+ :skill: 4
309
333
  -
310
334
  :type: :sprint
311
335
  :skill: 2
@@ -2,11 +2,16 @@ module SmashAndGrab::Abilities
2
2
  # @abstract
3
3
  class Ability
4
4
  attr_reader :skill, :owner
5
+ SKILL_LEVEL_DESCRIPTIONS = %w[Fair Good Excellent Heroic Legendary]
5
6
 
6
7
  def can_be_undone?; true; end
7
8
  def action_cost; @action_cost == :all ? owner.max_action_points : @action_cost; end
8
9
  def type; Inflector.underscore(Inflector.demodulize(self.class.name)).to_sym; end
9
10
 
11
+ def tip
12
+ "#{SKILL_LEVEL_DESCRIPTIONS[skill - 1]} #{type.capitalize} (#{'*' * skill})"
13
+ end
14
+
10
15
  protected
11
16
  def initialize(owner, data)
12
17
  @owner = owner
@@ -7,16 +7,22 @@ module SmashAndGrab::Abilities
7
7
 
8
8
  def target_valid?(tile); tile.object.is_a?(Objects::Entity) and tile.object.enemy?(owner); end
9
9
 
10
+ def tip
11
+ "#{super} attack in hand-to-hand combat"
12
+ end
13
+
10
14
  def initialize(owner, data)
11
15
  super(owner, data.merge(action_cost: 1))
12
16
  end
13
17
 
14
- def action_data(target_tile)
15
- super(target_tile).merge(
18
+ def action_data(target)
19
+ super(target.tile).merge(
16
20
  damage: random_damage
17
21
  )
18
22
  end
19
23
 
24
+ def target(data); owner.map.object_by_id(data[:target_id]); end
25
+
20
26
  def random_damage
21
27
  # 1..skill as damage in a bell-ish curve.
22
28
  (skill - 1).times.find_all { rand(2) == 1 }.size + 1
@@ -25,13 +31,13 @@ module SmashAndGrab::Abilities
25
31
  def do(data)
26
32
  super(data)
27
33
 
28
- owner.map.object_by_id(data[:target_id]).health -= data[:damage]
34
+ owner.melee(target(data), data[:damage])
29
35
  end
30
36
 
31
37
  def undo(data)
32
- target = owner.map.object_by_id(data[:target_id])
33
- target.health += data[:damage]
38
+ target = target(data)
34
39
  target.tile = owner.map.tile_at_grid(data[:target_position]) unless target.tile
40
+ owner.melee(target(data), -data[:damage])
35
41
 
36
42
  super(data)
37
43
  end
@@ -2,10 +2,30 @@ require_relative "ability"
2
2
 
3
3
  module SmashAndGrab::Abilities
4
4
  class Ranged < TargetedAbility
5
+ attr_reader :min_range, :max_range
6
+
5
7
  def can_undo?; false; end
6
8
 
9
+ # TODO: Take into account min/max range and LOS.
7
10
  def target_valid?(tile); !!(tile.object.is_a?(Objects::Entity) and tile.object.enemy?(owner)); end
8
11
 
12
+ def initialize(owner, data)
13
+ super(owner, data.merge(action_cost: 1))
14
+ @max_range = data[:max_range] || raise(ArgumentError, "no :max_range specified")
15
+ @min_range = data[:min_range] || raise(ArgumentError, "no :min_range specified")
16
+ end
17
+
18
+ def tip
19
+ "#{super} attack in ranged combat, at range #{min_range}..#{max_range}"
20
+ end
21
+
22
+ def to_json(*args)
23
+ super.merge(
24
+ min_range: @min_range,
25
+ max_range: @max_range,
26
+ ).to_json(*args)
27
+ end
28
+
9
29
  def action_data(target_tile)
10
30
  super(target_tile).merge!(
11
31
  damage: random_damage
@@ -21,6 +21,10 @@ module SmashAndGrab::Abilities
21
21
  [bonus.floor, 1].max
22
22
  end
23
23
 
24
+ def tip
25
+ "#{super} gain #{movement_bonus} movement points at cost of all actions"
26
+ end
27
+
24
28
  def action_data
25
29
  super().merge(
26
30
  movement_bonus: movement_bonus
@@ -4,7 +4,9 @@ module SmashAndGrab::Abilities
4
4
  # Create an ability based on class name.
5
5
  # @param owner [Entity]
6
6
  # @option data :type [String] underscored name of Ability to create.
7
- def self.ability(owner, data); const_get(Inflector.camelize data[:type]).new(owner, data); end
7
+ class << self
8
+ def ability(owner, data); const_get(Inflector.camelize data[:type]).new(owner, data); end
9
+ end
8
10
  end
9
11
 
10
12
 
@@ -0,0 +1,77 @@
1
+ module Fidgit
2
+ module Event
3
+ # Returned by {#subscribe} and can be used to {#unsubscribe}
4
+ class Subscription
5
+ attr_reader :publisher, :event, :handler
6
+
7
+ def initialize(publisher, event, handler)
8
+ @publisher, @event, @handler = publisher, event, handler
9
+ end
10
+
11
+ def unsubscribe
12
+ @publisher.unsubscribe self
13
+ end
14
+ end
15
+
16
+ class << self
17
+ def new_event_handlers
18
+ # Don't use Set, since it is not guaranteed to be ordered.
19
+ Hash.new {|h, k| h[k] = [] }
20
+ end
21
+ end
22
+
23
+ # @return [Subscription] Definition of this the handler created by this subscription, to be used with {#unsubscribe}
24
+ def subscribe(event, method = nil, &block)
25
+ raise ArgumentError, "Expected method or block for event handler" unless !block.nil? ^ !method.nil?
26
+ raise ArgumentError, "#{self.class} does not handle #{event.inspect}" unless events.include? event
27
+
28
+ @_event_handlers ||= Event.new_event_handlers
29
+ handler = method || block
30
+ @_event_handlers[event] << handler
31
+
32
+ Subscription.new self, event, handler
33
+ end
34
+
35
+ # @overload unsubscribe(subscription)
36
+ # Unsubscribe from a #{Subscription}, as returned from {#subscribe}
37
+ # @param subscription [Subscription]
38
+ # @return [Boolean] true if the handler was able to be deleted.
39
+ #
40
+ # @overload unsubscribe(handler)
41
+ # Unsubscribe from first event this handler has been used to subscribe to..
42
+ # @param handler [Block, Method] Event handler used.
43
+ # @return [Boolean] true if the handler was able to be deleted.
44
+ #
45
+ # @overload unsubscribe(event, handler)
46
+ # Unsubscribe from specific handler on particular event.
47
+ # @param event [Symbol] Name of event originally subscribed to.
48
+ # @param handler [Block, Method] Event handler used.
49
+ # @return [Boolean] true if the handler was able to be deleted.
50
+ #
51
+ def unsubscribe(*args)
52
+ @_event_handlers ||= Event.new_event_handlers
53
+
54
+ case args.size
55
+ when 1
56
+ case args.first
57
+ when Subscription
58
+ # Delete specific event handler.
59
+ subscription = args.first
60
+ raise ArgumentError, "Incorrect publisher for #{Subscription}: #{subscription.publisher}" unless subscription.publisher == self
61
+ unsubscribe subscription.event, subscription.handler
62
+ when Block, Method
63
+ # Delete first events that use the handler.
64
+ handler = args.first
65
+ !!@_event_handlers.find {|_, handlers| handlers.delete handler }
66
+ else
67
+ raise TypeError, "handler must be a #{Subscription}, Block or Method: #{args.first}"
68
+ end
69
+ when 2
70
+ event, handler = args
71
+ !!@_event_handlers[event].delete(handler)
72
+ else
73
+ raise ArgumentError, "Requires 1..2 arguments, but received #{args.size} arguments"
74
+ end
75
+ end
76
+ end
77
+ end
@@ -1,7 +1,35 @@
1
1
  module SmashAndGrab
2
2
  module Gui
3
3
  class EditorSelector < Fidgit::Vertical
4
- OBJECT_TABS = [:tiles, :walls, :objects, :entities, :vehicles]
4
+ OBJECT_TYPES = {
5
+ tiles: {
6
+ type: Tile,
7
+ num_columns: 2,
8
+ factor: 2,
9
+ },
10
+ walls: {
11
+ type: Wall,
12
+ num_columns: 3,
13
+ factor: 1,
14
+ },
15
+ objects: {
16
+ type: Objects::Static,
17
+ num_columns: 2,
18
+ factor: 1,
19
+ },
20
+ entities: {
21
+ type: Objects::Entity,
22
+ num_columns: 2,
23
+ factor: 1,
24
+ },
25
+ vehicles: {
26
+ type: Objects::Vehicle,
27
+ num_columns: 1,
28
+ factor: 0.5,
29
+ },
30
+ }
31
+
32
+ OBJECT_TABS = OBJECT_TYPES.keys
5
33
 
6
34
  def tab; @tabs_group.value; end
7
35
  def tab=(tab); @tabs_group.value = tab; end
@@ -33,7 +61,7 @@ class EditorSelector < Fidgit::Vertical
33
61
  scroll_options = { width: 200, height: 540 }
34
62
 
35
63
  @tab_windows[value] ||= Fidgit::ScrollWindow.new scroll_options do
36
- send("#{value}_window")
64
+ list_window value
37
65
  end
38
66
 
39
67
  @selector_window = @tab_windows[value]
@@ -83,91 +111,44 @@ class EditorSelector < Fidgit::Vertical
83
111
  end
84
112
  end
85
113
 
86
- protected
87
- def tiles_window
88
- buttons = group do
89
- vertical padding: 1 do
90
- radio_button 'Erase', :none
91
- grid padding: 0, num_columns: 2 do
92
- Tile.config.each_pair.sort.each do |type, data|
93
- next if type == :none
94
- radio_button '', type, icon: Tile.sprites[*data[:spritesheet_position]],
95
- tip: "Tile: #{type}", padding: 0, icon_options: { factor: 2 }
96
- end
97
- end
98
- end
114
+ public
115
+ def icon_for(type, list_type = tab)
116
+ if type == :erase or type == :none
117
+ nil
118
+ else
119
+ klass = OBJECT_TYPES[list_type][:type]
120
+ spritesheet_position = if list_type == :walls
121
+ klass.config[type][:spritesheet_positions][:vertical]
122
+ else
123
+ klass.config[type][:spritesheet_position]
124
+ end
125
+
126
+ klass.sprites[*spritesheet_position]
99
127
  end
100
-
101
- buttons.value = :none
102
128
  end
103
129
 
104
130
  protected
105
- def entities_window
106
- buttons = group do
107
- vertical padding: 1 do
108
- radio_button 'Erase', :erase
109
- grid padding: 0, num_columns: 2 do
110
- Objects::Entity.config.each_pair.sort.each do |type, data|
111
- radio_button '', type, icon: Objects::Entity.sprites[*data[:spritesheet_position]],
112
- tip: "Entity: #{type} (#{data[:faction]})", padding: 0
113
- end
114
- end
115
- end
116
- end
131
+ def list_window(list_type)
132
+ erase_name = (list_type == :walls) ? :none : :erase
117
133
 
118
- buttons.value = :erase
119
- end
120
-
121
- protected
122
- def objects_window
123
134
  buttons = group do
124
135
  vertical padding: 1 do
125
- radio_button 'Erase', :erase
126
- grid padding: 0, num_columns: 2 do
127
- Objects::Static.config.each_pair.sort.each do |type, data|
128
- radio_button '', type, icon: Objects::Static.sprites[*data[:spritesheet_position]],
129
- tip: "Object: #{type}", padding: 0
130
- end
131
- end
132
- end
133
- end
136
+ radio_button 'Erase', erase_name
134
137
 
135
- buttons.value = :erase
136
- end
138
+ grid padding: 0, num_columns: OBJECT_TYPES[list_type][:num_columns] do
139
+ OBJECT_TYPES[list_type][:type].config.each_pair.sort.each do |type, config|
140
+ icon = icon_for(type, list_type)
141
+ next unless icon
137
142
 
138
- protected
139
- def vehicles_window
140
- buttons = group do
141
- vertical padding: 1 do
142
- radio_button 'Erase', :erase
143
- grid padding: 0, num_columns: 1 do
144
- Objects::Vehicle.config.each_pair.sort.each do |type, data|
145
- radio_button '', type, icon: Objects::Vehicle.sprites[*data[:spritesheet_position]],
146
- tip: "Vehicle: #{type}", padding: 0, icon_options: { factor: 0.5 }
147
- end
148
- end
149
- end
150
- end
151
-
152
- buttons.value = :erase
153
- end
154
-
155
- protected
156
- def walls_window
157
- buttons = group do
158
- vertical padding: 1 do
159
- radio_button 'Erase', :none
160
- grid padding: 0, num_columns: 3 do
161
- Wall.config.each_pair.sort.each do |type, data|
162
- next if type == :none
163
- radio_button '', type, icon: Wall.sprites[*(data[:spritesheet_positions][:vertical])],
164
- tip: "Wall: #{type}", padding: 0
143
+ radio_button '', type, icon: icon, padding: 0,
144
+ icon_options: { factor: OBJECT_TYPES[list_type][:factor] },
145
+ tip: "#{list_type.capitalize}: #{type} #{list_type == :entities ? "(#{config[:faction]})" : ''}"
165
146
  end
166
147
  end
167
148
  end
168
149
  end
169
150
 
170
- buttons.value = :none
151
+ buttons.value = erase_name
171
152
  end
172
153
  end
173
154
  end