smash_and_grab 0.0.5alpha → 0.0.6alpha
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/{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
|