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.
- data/Gemfile.lock +1 -1
- data/README.md +31 -16
- data/config/gui/schema.yml +3 -2
- data/config/map/entities.yml +36 -12
- data/lib/smash_and_grab/abilities/ability.rb +5 -0
- data/lib/smash_and_grab/abilities/melee.rb +11 -5
- data/lib/smash_and_grab/abilities/ranged.rb +20 -0
- data/lib/smash_and_grab/abilities/sprint.rb +4 -0
- data/lib/smash_and_grab/abilities.rb +3 -1
- data/lib/smash_and_grab/fidgit_ext/event.rb +77 -0
- data/lib/smash_and_grab/gui/editor_selector.rb +54 -73
- data/lib/smash_and_grab/gui/entity_panel.rb +110 -0
- data/lib/smash_and_grab/gui/entity_summary.rb +9 -8
- data/lib/smash_and_grab/gui/game_log.rb +44 -0
- data/lib/smash_and_grab/gui/info_panel.rb +39 -95
- data/lib/smash_and_grab/gui/object_panel.rb +37 -0
- data/lib/smash_and_grab/gui/scenario_panel.rb +21 -0
- data/lib/smash_and_grab/history/editor_actions/place_object.rb +1 -1
- data/lib/smash_and_grab/main.rb +11 -16
- data/lib/smash_and_grab/map/map.rb +1 -0
- data/lib/smash_and_grab/map/tile.rb +6 -3
- data/lib/smash_and_grab/map/wall.rb +4 -2
- data/lib/smash_and_grab/mouse_selection.rb +103 -46
- data/lib/smash_and_grab/objects/entity.rb +219 -30
- data/lib/smash_and_grab/objects/static.rb +7 -5
- data/lib/smash_and_grab/objects/vehicle.rb +7 -5
- data/lib/smash_and_grab/objects/world_object.rb +13 -3
- data/lib/smash_and_grab/path.rb +13 -7
- data/lib/smash_and_grab/players/player.rb +15 -10
- data/lib/smash_and_grab/states/edit_level.rb +17 -0
- data/lib/smash_and_grab/states/play_level.rb +20 -10
- data/lib/smash_and_grab/version.rb +1 -1
- data/lib/smash_and_grab.rb +18 -14
- data/test/smash_and_grab/abilities/melee_test.rb +37 -39
- data/test/teststrap.rb +3 -3
- metadata +21 -16
data/Gemfile.lock
CHANGED
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
|
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
|
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 (
|
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
|
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
|
-
|
31
|
-
|
32
|
-
|
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://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
|
data/config/gui/schema.yml
CHANGED
data/config/map/entities.yml
CHANGED
@@ -16,12 +16,12 @@
|
|
16
16
|
:abilities:
|
17
17
|
-
|
18
18
|
:type: :melee
|
19
|
-
:skill:
|
19
|
+
:skill: 3
|
20
20
|
-
|
21
21
|
:type: :ranged
|
22
|
-
:skill:
|
23
|
-
:
|
24
|
-
:
|
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:
|
59
|
+
:action_points: 2
|
60
60
|
:health: 15
|
61
61
|
:abilities:
|
62
62
|
-
|
63
63
|
:type: :melee
|
64
|
-
:skill:
|
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:
|
73
|
+
:action_points: 1
|
74
74
|
:health: 10
|
75
75
|
:abilities:
|
76
76
|
-
|
77
77
|
:type: :melee
|
78
|
-
:skill:
|
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:
|
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:
|
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:
|
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(
|
15
|
-
super(
|
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.
|
34
|
+
owner.melee(target(data), data[:damage])
|
29
35
|
end
|
30
36
|
|
31
37
|
def undo(data)
|
32
|
-
target =
|
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
|
@@ -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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
87
|
-
def
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
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
|
106
|
-
|
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',
|
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
|
-
|
136
|
-
|
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
|
-
|
139
|
-
|
140
|
-
|
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 =
|
151
|
+
buttons.value = erase_name
|
171
152
|
end
|
172
153
|
end
|
173
154
|
end
|