smash_and_grab 0.0.3alpha → 0.0.5alpha

Sign up to get free protection for your applications and to get access to all the features.
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