smash_and_grab 0.0.5alpha → 0.0.6alpha
Sign up to get free protection for your applications and to get access to all the features.
- data/{CHANGELOG.txt → CHANGELOG.md} +0 -0
- data/Gemfile.lock +8 -4
- data/LICENSE.txt +20 -0
- data/README.md +30 -14
- data/Rakefile +2 -2
- data/config/lang/objects/entities/en.yml +134 -0
- data/config/lang/objects/static/en.yml +8 -0
- data/config/lang/objects/vehicles/en.yml +11 -0
- data/config/map/entities.yml +42 -38
- data/lib/smash_and_grab.rb +5 -0
- data/lib/smash_and_grab/abilities.rb +1 -1
- data/lib/smash_and_grab/abilities/ability.rb +45 -3
- data/lib/smash_and_grab/abilities/drop.rb +38 -0
- data/lib/smash_and_grab/abilities/melee.rb +4 -6
- data/lib/smash_and_grab/abilities/pick_up.rb +33 -0
- data/lib/smash_and_grab/abilities/ranged.rb +18 -12
- data/lib/smash_and_grab/abilities/sprint.rb +11 -7
- data/lib/smash_and_grab/chingu_ext/basic_game_object.rb +26 -0
- data/lib/smash_and_grab/game_window.rb +5 -1
- data/lib/smash_and_grab/gui/entity_panel.rb +26 -10
- data/lib/smash_and_grab/gui/entity_summary.rb +19 -11
- data/lib/smash_and_grab/gui/game_log.rb +6 -2
- data/lib/smash_and_grab/gui/info_panel.rb +7 -4
- data/lib/smash_and_grab/gui/object_panel.rb +6 -2
- data/lib/smash_and_grab/gui/scenario_panel.rb +4 -0
- data/lib/smash_and_grab/history/action_history.rb +1 -1
- data/lib/smash_and_grab/main.rb +7 -3
- data/lib/smash_and_grab/map/faction.rb +26 -8
- data/lib/smash_and_grab/map/map.rb +21 -12
- data/lib/smash_and_grab/map/tile.rb +29 -2
- data/lib/smash_and_grab/map/wall.rb +2 -2
- data/lib/smash_and_grab/mixins/has_contents.rb +38 -0
- data/lib/smash_and_grab/mixins/line_of_sight.rb +129 -0
- data/lib/smash_and_grab/mixins/pathfinding.rb +145 -0
- data/lib/smash_and_grab/mouse_selection.rb +107 -36
- data/lib/smash_and_grab/objects/entity.rb +311 -260
- data/lib/smash_and_grab/objects/floating_text.rb +0 -1
- data/lib/smash_and_grab/objects/static.rb +10 -3
- data/lib/smash_and_grab/objects/vehicle.rb +7 -2
- data/lib/smash_and_grab/objects/world_object.rb +10 -3
- data/lib/smash_and_grab/path.rb +38 -12
- data/lib/smash_and_grab/players/ai.rb +91 -0
- data/lib/smash_and_grab/players/human.rb +9 -0
- data/lib/smash_and_grab/players/player.rb +16 -65
- data/lib/smash_and_grab/players/remote.rb +9 -0
- data/lib/smash_and_grab/sprite_sheet.rb +9 -0
- data/lib/smash_and_grab/states/edit_level.rb +15 -4
- data/lib/smash_and_grab/states/main_menu.rb +16 -4
- data/lib/smash_and_grab/states/play_level.rb +88 -28
- data/lib/smash_and_grab/states/world.rb +17 -9
- data/lib/smash_and_grab/version.rb +1 -1
- data/lib/smash_and_grab/z_order.rb +6 -5
- data/media/images/path.png +0 -0
- data/media/images/tile_selection.png +0 -0
- data/media/images/tiles_selection.png +0 -0
- data/smash_and_grab.gemspec +2 -2
- data/tasks/create_portraits.rb +39 -0
- data/tasks/outline_images.rb +56 -0
- data/test/smash_and_grab/abilities/drop_test.rb +68 -0
- data/test/smash_and_grab/abilities/melee_test.rb +4 -4
- data/test/smash_and_grab/abilities/pick_up_test.rb +68 -0
- data/test/smash_and_grab/abilities/ranged_test.rb +105 -0
- data/test/smash_and_grab/abilities/sprint_test.rb +55 -25
- data/test/smash_and_grab/map/faction_test.rb +18 -16
- data/test/smash_and_grab/map/map_test.rb +9 -4
- metadata +51 -19
- data/lib/smash_and_grab/fidgit_ext/event.rb +0 -77
@@ -4,6 +4,7 @@ module SmashAndGrab
|
|
4
4
|
module States
|
5
5
|
class EditLevel < World
|
6
6
|
PLACEMENT_COLOR = Color.rgba(255, 255, 255, 190)
|
7
|
+
FACTIONS = [:baddies, :goodies, :bystanders]
|
7
8
|
|
8
9
|
def initialize(file)
|
9
10
|
super()
|
@@ -13,13 +14,23 @@ class EditLevel < World
|
|
13
14
|
|
14
15
|
@selected_wall = nil
|
15
16
|
|
16
|
-
|
17
|
+
factions = FACTIONS.map do |f|
|
18
|
+
Factions.const_get(f.capitalize).new
|
19
|
+
end
|
20
|
+
|
21
|
+
load_game file, factions
|
17
22
|
|
18
23
|
on_input :right_mouse_button do
|
19
24
|
@selector.pick_up(@hover_tile, @hover_wall)
|
20
25
|
end
|
21
26
|
end
|
22
27
|
|
28
|
+
def assign_entities_to_factions
|
29
|
+
map.world_objects.grep(Objects::Entity).each do |o|
|
30
|
+
o.faction = map.factions[FACTIONS.index o.default_faction_type]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
23
34
|
def create_gui
|
24
35
|
@container = Fidgit::Container.new do |container|
|
25
36
|
@minimap = Gui::Minimap.new parent: container
|
@@ -58,8 +69,8 @@ class EditLevel < World
|
|
58
69
|
load_game @editing_file
|
59
70
|
end
|
60
71
|
|
61
|
-
def load_game(file)
|
62
|
-
super
|
72
|
+
def load_game(file, factions)
|
73
|
+
super file, factions, start: false
|
63
74
|
@editing_file = file
|
64
75
|
@actions = EditorActionHistory.new
|
65
76
|
end
|
@@ -194,4 +205,4 @@ class EditLevel < World
|
|
194
205
|
end
|
195
206
|
end
|
196
207
|
end
|
197
|
-
end
|
208
|
+
end
|
@@ -11,7 +11,7 @@ class MainMenu < Fidgit::GuiState
|
|
11
11
|
|
12
12
|
@container.background_color = Color.rgb(0, 0, 25)
|
13
13
|
|
14
|
-
vertical align: :center do
|
14
|
+
vertical align: :center, padding: 0, spacing: 0 do
|
15
15
|
horizontal align: :center do
|
16
16
|
image_frame Objects::Static.sprites[1, 0], factor: 3
|
17
17
|
|
@@ -28,9 +28,21 @@ class MainMenu < Fidgit::GuiState
|
|
28
28
|
image_frame Objects::Entity.sprites[3, 1], factor: 4
|
29
29
|
|
30
30
|
vertical align: :center do
|
31
|
-
options = { width:
|
32
|
-
button "
|
33
|
-
push_game_state States::PlayLevel.new(GAME_FILE)
|
31
|
+
options = { width: 200, justify: :center }
|
32
|
+
button "Single Player", options do
|
33
|
+
push_game_state States::PlayLevel.new(GAME_FILE, Players::Human.new, Players::AI.new)
|
34
|
+
end
|
35
|
+
|
36
|
+
button "Co-op", options do
|
37
|
+
push_game_state States::PlayLevel.new(GAME_FILE, [Players::Human.new, Players::Human.new], Players::AI.new)
|
38
|
+
end
|
39
|
+
|
40
|
+
button "Hot-seat", options do
|
41
|
+
push_game_state States::PlayLevel.new(GAME_FILE, Players::Human.new, Players::Human.new)
|
42
|
+
end
|
43
|
+
|
44
|
+
button "AI vs AI", options do
|
45
|
+
push_game_state States::PlayLevel.new(GAME_FILE, Players::AI.new, Players::AI.new)
|
34
46
|
end
|
35
47
|
|
36
48
|
button "Edit", options do
|
@@ -5,63 +5,116 @@ module States
|
|
5
5
|
class PlayLevel < World
|
6
6
|
include Fidgit::Event
|
7
7
|
|
8
|
-
attr_reader :info_panel
|
8
|
+
attr_reader :info_panel, :cursor_world_x, :cursor_world_y
|
9
9
|
|
10
10
|
event :game_info
|
11
11
|
event :game_heading
|
12
12
|
|
13
|
-
|
13
|
+
# Players is villains
|
14
|
+
def initialize(file, baddies_players, goodies_players)
|
14
15
|
super()
|
15
16
|
|
16
17
|
add_inputs(space: :end_turn)
|
17
18
|
|
18
|
-
@players =
|
19
|
+
@players = {
|
20
|
+
baddies: Array(baddies_players),
|
21
|
+
goodies: Array(goodies_players),
|
22
|
+
bystanders: [Players::AI.new],
|
23
|
+
}
|
19
24
|
|
20
25
|
@quicksaved = false
|
26
|
+
@cursor_world_x = @cursor_world_x = nil
|
21
27
|
|
22
|
-
|
28
|
+
factions = []
|
23
29
|
|
24
|
-
@players.
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
publish :game_info, ""
|
30
|
-
publish :game_heading, "#{player.faction}' turn (#{Inflector.demodulize player.class})"
|
31
|
-
publish :game_info, ""
|
30
|
+
@players.each_pair do |faction_name, players|
|
31
|
+
players.each do |player|
|
32
|
+
new_faction = Factions.const_get(faction_name.capitalize).new
|
33
|
+
factions << new_faction
|
34
|
+
player.faction = new_faction
|
32
35
|
end
|
33
36
|
end
|
34
37
|
|
38
|
+
load_game file, factions
|
39
|
+
|
40
|
+
# If loading a level, start the first turn, otherwise just keep going.
|
41
|
+
name = File.basename(file).chomp(File.extname(file))
|
42
|
+
if File.extname(file) == ".sgl"
|
43
|
+
publish :game_heading, "=== Started #{name} ==="
|
44
|
+
publish :game_info, ""
|
45
|
+
map.factions.first.start_turn
|
46
|
+
else
|
47
|
+
faction = map.active_faction
|
48
|
+
publish :game_heading, "=== Resuming #{name} in turn #{map.turn + 1} ==="
|
49
|
+
publish :game_info, ""
|
50
|
+
publish :game_heading,faction.class::TEXT_COLOR.colorize("#{faction.name}' turn (#{Inflector.demodulize faction.player.class})")
|
51
|
+
publish :game_info, ""
|
52
|
+
end
|
53
|
+
|
35
54
|
save_game_as AUTOSAVE_FILE
|
36
55
|
|
37
56
|
@mouse_selection = MouseSelection.new @map
|
38
57
|
end
|
39
58
|
|
59
|
+
def assign_entities_to_factions
|
60
|
+
factions_by_type = map.factions.group_by {|f| Inflector.demodulize(f.class.name).downcase.to_sym }
|
61
|
+
factions_by_type.each_pair do |faction_name, factions|
|
62
|
+
entities = map.world_objects.grep(Objects::Entity).find_all {|o| o.default_faction_type == faction_name }
|
63
|
+
# Split them up as evenly as possible if more than one player is controlling them.
|
64
|
+
entities_per_faction = entities.size.fdiv(factions.size).ceil
|
65
|
+
entities.each_slice(entities_per_faction).with_index do |entities, i|
|
66
|
+
entities.each {|e| e.faction = factions[i] }
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
40
71
|
def create_gui
|
41
72
|
@container = Fidgit::Container.new do |container|
|
42
73
|
@minimap = Gui::Minimap.new parent: container
|
43
74
|
|
44
|
-
# Unit roster.
|
45
|
-
@
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
75
|
+
# Unit roster for each human-controlled faction.
|
76
|
+
@summaries_lists = {}
|
77
|
+
|
78
|
+
# Create a summary list for each human-controlled faction.
|
79
|
+
@map.factions.each do |faction|
|
80
|
+
if faction.player.is_a? Players::Human
|
81
|
+
@summaries_lists[faction] = Fidgit::Vertical.new padding: 4, spacing: 4 do |packer|
|
82
|
+
# Put each entity into the list.
|
83
|
+
faction.entities.each do |entity|
|
84
|
+
summary = Gui::EntitySummary.new entity, parent: packer
|
85
|
+
summary.subscribe :left_mouse_button do
|
86
|
+
@mouse_selection.selected = entity if entity.alive?
|
87
|
+
@info_panel.object = entity
|
88
|
+
end
|
89
|
+
end
|
52
90
|
end
|
91
|
+
|
92
|
+
# At the start of the turn, change in our summary list.
|
93
|
+
# Means the last human player's list will be shown during the AI turns.
|
94
|
+
faction.subscribe :turn_started do
|
95
|
+
@summary_bar.clear
|
96
|
+
@summary_bar.add @summaries_lists[faction]
|
97
|
+
end
|
98
|
+
|
99
|
+
# TODO: Add and remove entities to the lists as unit list changes.
|
100
|
+
#faction.subscribe :entity_added do
|
101
|
+
#end
|
102
|
+
#faction.subscribe :entity_removed do
|
103
|
+
#end
|
53
104
|
end
|
54
105
|
end
|
55
106
|
|
107
|
+
# Will contain the summary lists.
|
108
|
+
@summary_bar = vertical parent: container, padding: 0, spacing: 0, background_color: Color::BLACK
|
109
|
+
|
56
110
|
# Info panel.
|
57
111
|
@info_panel = Gui::InfoPanel.new self, parent: container
|
58
|
-
@info_panel.object = @map.baddies[0]
|
59
112
|
|
60
113
|
# Button box.
|
61
114
|
@button_box = vertical parent: container, padding: 4, spacing: 8, width: 150, background_color: Color::BLACK do
|
62
115
|
@turn_label = label " ", font_height: 14
|
63
116
|
|
64
|
-
button "End turn" do
|
117
|
+
@end_turn_button = button "End turn" do
|
65
118
|
end_turn
|
66
119
|
end
|
67
120
|
|
@@ -96,7 +149,7 @@ class PlayLevel < World
|
|
96
149
|
selection = @mouse_selection.selected
|
97
150
|
@mouse_selection.selected = nil
|
98
151
|
@map.actions.redo if @map.actions.can_redo?
|
99
|
-
@mouse_selection.selected =
|
152
|
+
@mouse_selection.selected = selection if selection
|
100
153
|
end
|
101
154
|
|
102
155
|
def map=(map)
|
@@ -125,9 +178,13 @@ class PlayLevel < World
|
|
125
178
|
$window.mouse_y >= 0 and $window.mouse_y < $window.height and
|
126
179
|
@container.each.none? {|e| e.hit? $window.mouse_x, $window.mouse_y }
|
127
180
|
|
128
|
-
@
|
129
|
-
|
181
|
+
@cursor_world_x = (@camera_offset_x + $window.mouse_x) / @zoom
|
182
|
+
@cursor_world_y = (@camera_offset_y + $window.mouse_y) / @zoom
|
183
|
+
|
184
|
+
@map.tile_at_position @cursor_world_x, @cursor_world_y
|
130
185
|
else
|
186
|
+
@cursor_world_x = @cursor_world_y = nil
|
187
|
+
|
131
188
|
nil
|
132
189
|
end
|
133
190
|
|
@@ -139,17 +196,20 @@ class PlayLevel < World
|
|
139
196
|
|
140
197
|
@turn_label.text = "Turn: #{@map.turn + 1} (#{@map.active_faction})"
|
141
198
|
|
142
|
-
|
143
|
-
@
|
199
|
+
usable = @map.active_faction.player.human? && !@map.busy?
|
200
|
+
@end_turn_button.enabled = usable
|
201
|
+
@undo_button.enabled = usable && @map.actions.can_undo?
|
202
|
+
@redo_button.enabled = usable && @map.actions.can_redo?
|
144
203
|
end
|
145
204
|
|
146
205
|
def quickload
|
147
206
|
if @quicksaved
|
148
|
-
switch_game_state self.class.new(QUICKSAVE_FILE)
|
207
|
+
switch_game_state self.class.new(QUICKSAVE_FILE, @players[:baddies], @players[:goodies])
|
149
208
|
end
|
150
209
|
end
|
151
210
|
|
152
211
|
def quicksave
|
212
|
+
publish :game_heading, "<<< Quick-saved >>>"
|
153
213
|
save_game_as QUICKSAVE_FILE
|
154
214
|
@quicksaved = true
|
155
215
|
end
|
@@ -18,14 +18,9 @@ class World < Fidgit::GuiState
|
|
18
18
|
QUICKSAVE_FILE = File.expand_path("quicksave.sgs", SAVE_PATH)
|
19
19
|
AUTOSAVE_FILE = File.expand_path("autosave.sgs", SAVE_PATH)
|
20
20
|
|
21
|
-
def
|
22
|
-
@map = map
|
23
|
-
@map.record_grid GRID_COLOR
|
24
|
-
|
25
|
-
@camera_offset_x, @camera_offset_y = [0, -@map.to_rect.center_y]
|
26
|
-
|
27
|
-
create_gui
|
21
|
+
def create_gui; raise NotImplementedError; end
|
28
22
|
|
23
|
+
def create_minimap
|
29
24
|
@minimap.map = @map
|
30
25
|
|
31
26
|
@map.subscribe :tile_contents_changed do |map, tile|
|
@@ -94,7 +89,7 @@ class World < Fidgit::GuiState
|
|
94
89
|
File.open("#{file}.json", "w") {|f| f.write json } # DEBUG ONLY!
|
95
90
|
end
|
96
91
|
|
97
|
-
def load_game(file)
|
92
|
+
def load_game(file, factions, options = {})
|
98
93
|
t = Time.now
|
99
94
|
|
100
95
|
json = Zlib::GzipReader.open(file) do |gz|
|
@@ -103,11 +98,24 @@ class World < Fidgit::GuiState
|
|
103
98
|
|
104
99
|
data = JSON.parse(json).symbolize
|
105
100
|
|
106
|
-
|
101
|
+
@map = Map.new data, factions, options
|
102
|
+
@map.record_grid GRID_COLOR
|
103
|
+
|
104
|
+
@camera_offset_x, @camera_offset_y = [0, -@map.to_rect.center_y]
|
105
|
+
|
106
|
+
assign_entities_to_factions
|
107
|
+
|
108
|
+
# Make sure that every entity has picked up the object they had before.
|
109
|
+
map.factions.each {|f| f.entities.each {|e| e.setup_contents } }
|
110
|
+
|
111
|
+
create_gui
|
112
|
+
create_minimap
|
107
113
|
|
108
114
|
log.info { "Loaded game from #{file} [#{File.size(file)} bytes] in #{"%.3f" % (Time.now - t) }s" }
|
109
115
|
end
|
110
116
|
|
117
|
+
def assign_entities_to_factions; raise NotImplementedError; end
|
118
|
+
|
111
119
|
def autosave
|
112
120
|
save_game_as AUTOSAVE_FILE
|
113
121
|
end
|
@@ -1,12 +1,13 @@
|
|
1
1
|
module SmashAndGrab
|
2
2
|
class ZOrder
|
3
3
|
BACKGROUND = -Float::INFINITY
|
4
|
-
TILES = -
|
5
|
-
SHADOWS = -
|
6
|
-
TILE_SELECTION = -
|
7
|
-
PATH = -
|
8
|
-
# Objects -
|
4
|
+
TILES = -99_999
|
5
|
+
SHADOWS = -99_998
|
6
|
+
TILE_SELECTION = -99_997
|
7
|
+
PATH = -99_996
|
8
|
+
# Objects -1_000 .. +1_000
|
9
9
|
|
10
|
+
BEHIND_GUI = 1_000_000
|
10
11
|
GUI = Float::INFINITY
|
11
12
|
end
|
12
13
|
end
|
data/media/images/path.png
CHANGED
Binary file
|
Binary file
|
Binary file
|
data/smash_and_grab.gemspec
CHANGED
@@ -25,9 +25,9 @@ END
|
|
25
25
|
|
26
26
|
s.add_runtime_dependency "gosu", "~> 0.7.41"
|
27
27
|
s.add_runtime_dependency "chingu", "~> 0.9rc7"
|
28
|
-
s.add_runtime_dependency "fidgit", "~> 0.1
|
28
|
+
s.add_runtime_dependency "fidgit", "~> 0.2.1"
|
29
29
|
s.add_runtime_dependency "texplay", "~> 0.3"
|
30
|
-
|
30
|
+
s.add_runtime_dependency "r18n-desktop", "~> 0.4.14"
|
31
31
|
|
32
32
|
s.add_development_dependency "releasy", "~> 0.2.2"
|
33
33
|
s.add_development_dependency "rake", "~> 0.9.2.2"
|
@@ -0,0 +1,39 @@
|
|
1
|
+
PORTRAIT_IMAGES = [
|
2
|
+
# in, out, in-size, columns, out-rect.
|
3
|
+
["entities.png", "entity_portraits.png", [66, 66], 8, [14, 10, 36, 36]],
|
4
|
+
]
|
5
|
+
|
6
|
+
desc "Process images (cut out a portrait of each character)"
|
7
|
+
task create_portraits: :outline_images do
|
8
|
+
require 'texplay'
|
9
|
+
require_relative '../lib/texplay_ext/color'
|
10
|
+
require_relative '../lib/texplay_ext/image'
|
11
|
+
require_relative '../lib/texplay_ext/window'
|
12
|
+
|
13
|
+
puts "=== Creating portraits ===\n\n"
|
14
|
+
|
15
|
+
$window = Gosu::Window.new(100, 100, false)
|
16
|
+
|
17
|
+
PORTRAIT_IMAGES.each do |image_in_name, image_out_name, (width, height), num_columns, (rect_x, rect_y, rect_width, rect_height)|
|
18
|
+
puts "Making portraits from #{image_in_name}"
|
19
|
+
|
20
|
+
sprites = Gosu::Image.load_tiles($window, File.expand_path(image_in_name, MODIFIED_IMAGE_PATH), width, height, false)
|
21
|
+
sprites.each(&:refresh_cache)
|
22
|
+
|
23
|
+
new_image = Gosu::Image.create rect_width * num_columns,
|
24
|
+
rect_height * (sprites.size / num_columns)
|
25
|
+
new_image.refresh_cache
|
26
|
+
|
27
|
+
print "\n Splicing: "
|
28
|
+
sprites.each.with_index do |sprite, i|
|
29
|
+
row, column = i.divmod num_columns
|
30
|
+
new_image.splice sprite, column * rect_width, row * rect_height,
|
31
|
+
crop: [rect_x, rect_y, rect_x + rect_width, rect_y + rect_height]
|
32
|
+
print '.'
|
33
|
+
end
|
34
|
+
|
35
|
+
puts "\n\n"
|
36
|
+
|
37
|
+
new_image.save(File.expand_path(image_out_name, MODIFIED_IMAGE_PATH))
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
ORIGINAL_IMAGE_PATH = File.expand_path("../../raw_media/images", __FILE__)
|
2
|
+
MODIFIED_IMAGE_PATH = File.expand_path("../../media/images", __FILE__)
|
3
|
+
|
4
|
+
IMAGES = [
|
5
|
+
["entities.png", [32, 32], 8],
|
6
|
+
["objects.png", [32, 32], 8],
|
7
|
+
["vehicles.png", [128, 128], 3],
|
8
|
+
]
|
9
|
+
|
10
|
+
desc "Process images (double in size and add an outline)"
|
11
|
+
task :outline_images do
|
12
|
+
require 'texplay'
|
13
|
+
require_relative '../lib/texplay_ext/color'
|
14
|
+
require_relative '../lib/texplay_ext/image'
|
15
|
+
require_relative '../lib/texplay_ext/window'
|
16
|
+
|
17
|
+
puts "=== Processing images ===\n\n"
|
18
|
+
|
19
|
+
$window = Gosu::Window.new(100, 100, false)
|
20
|
+
|
21
|
+
IMAGES.each do |image_name, (width, height), num_columns|
|
22
|
+
puts "Processing #{image_name}"
|
23
|
+
|
24
|
+
sprites = Gosu::Image.load_tiles($window, File.expand_path(image_name, ORIGINAL_IMAGE_PATH), width, height, false)
|
25
|
+
sprites.each(&:refresh_cache)
|
26
|
+
|
27
|
+
print " Enlarging: "
|
28
|
+
large_sprites = sprites.map do |sprite|
|
29
|
+
print '.'
|
30
|
+
sprite.enlarge 2
|
31
|
+
end
|
32
|
+
|
33
|
+
print "\n Outlining: "
|
34
|
+
large_outlined = large_sprites.map do |sprite|
|
35
|
+
print '.'
|
36
|
+
sprite.outline
|
37
|
+
end
|
38
|
+
|
39
|
+
new_image = Gosu::Image.create large_outlined.first.width * num_columns,
|
40
|
+
large_outlined.first.height * large_outlined.size / num_columns
|
41
|
+
new_image.refresh_cache
|
42
|
+
|
43
|
+
print "\n Splicing: "
|
44
|
+
large_outlined.each.with_index do |sprite, i|
|
45
|
+
sprite.clear(dest_ignore: :alpha, color: Gosu::Color.rgb(50, 50, 50))
|
46
|
+
sprite.splice large_sprites[i], 1, 1, alpha_blend: true
|
47
|
+
row, column = i.divmod num_columns
|
48
|
+
new_image.splice sprite, column * sprite.width, row * sprite.height
|
49
|
+
print '.'
|
50
|
+
end
|
51
|
+
|
52
|
+
puts "\n\n"
|
53
|
+
|
54
|
+
new_image.save(File.expand_path(image_name, MODIFIED_IMAGE_PATH))
|
55
|
+
end
|
56
|
+
end
|