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.
- 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://i.creativecommons.org/l/by-sa/3.0/88x31.png
|
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
|
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
|