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
@@ -16,26 +16,34 @@ class EntitySummary < Fidgit::Vertical
|
|
16
16
|
|
17
17
|
@name = label "", font_height: 15
|
18
18
|
|
19
|
-
horizontal padding: 0, spacing: 4 do
|
20
|
-
@portrait = image_frame nil,
|
19
|
+
@box = horizontal padding: 0, spacing: 4 do
|
20
|
+
@portrait = image_frame nil, background_color: Color::GRAY,
|
21
21
|
border_thickness: 1, border_color: Color::BLACK
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
@action_points = label "", font_height: 15
|
26
|
-
@movement_points = label "", font_height: 15
|
27
|
-
end
|
23
|
+
# Just to get a position to place the stats box.
|
24
|
+
@stats_position = vertical padding: 0
|
28
25
|
end
|
29
26
|
|
30
|
-
|
27
|
+
self.entity = entity
|
28
|
+
end
|
29
|
+
|
30
|
+
def draw
|
31
|
+
super
|
32
|
+
@entity.draw_stat_bars x: @stats_position.x, y: @stats_position.y + 1, zorder: z, factor_x: 6, factor_y: 6
|
33
|
+
|
34
|
+
if @entity.contents
|
35
|
+
# TODO: Measure the sprite properly.
|
36
|
+
@entity.contents.image.draw x + width - 10, y - 12, z
|
37
|
+
end
|
31
38
|
end
|
32
39
|
|
33
40
|
public
|
34
41
|
def update_details(entity)
|
35
|
-
|
36
|
-
|
37
|
-
@action_points.text = "AP: #{entity.ap}"
|
42
|
+
self.tip = "HP: #{entity.hp} / #{entity.max_hp}; MP: #{entity.mp} / #{entity.max_mp}; AP: #{entity.ap} / #{entity.max_ap}"
|
43
|
+
|
38
44
|
@portrait.image = entity.portrait
|
45
|
+
@name.color = entity.alive? ? Color::WHITE : Color::GRAY
|
46
|
+
@portrait.enabled = entity.alive?
|
39
47
|
end
|
40
48
|
|
41
49
|
public
|
@@ -4,6 +4,7 @@ module SmashAndGrab
|
|
4
4
|
include Log
|
5
5
|
|
6
6
|
MAX_ITEMS = 100
|
7
|
+
HEADING_COLOR = Color.rgb(200, 200, 230)
|
7
8
|
|
8
9
|
def initialize(state, options = {})
|
9
10
|
options = {
|
@@ -16,18 +17,21 @@ module SmashAndGrab
|
|
16
17
|
|
17
18
|
@scroll_window = scroll_window width: 420, height: 72, padding: 0 do
|
18
19
|
# TODO: Text-area "editable(?)" seem broken. They don't prevent editing while also allowing copy/pasting.
|
19
|
-
@text = text_area width: 400, font_height: 14,
|
20
|
+
@text = text_area width: 400, font_height: 14, editable: false
|
20
21
|
end
|
21
22
|
|
22
23
|
@scroll_window.background_color = @text.background_color
|
23
24
|
|
24
25
|
state.subscribe :game_info do |_, text|
|
25
26
|
append text
|
27
|
+
text = text.gsub /<[^>]*>/, ''
|
26
28
|
log.info { "game_info: #{text}" }
|
27
29
|
end
|
28
30
|
|
29
31
|
state.subscribe :game_heading do |_, text|
|
30
|
-
|
32
|
+
|
33
|
+
append HEADING_COLOR.colorize("{ #{text} }")
|
34
|
+
text = text.gsub /<[^>]*>/, ''
|
31
35
|
log.info { "game_heading: #{text}" }
|
32
36
|
end
|
33
37
|
end
|
@@ -15,17 +15,20 @@ module SmashAndGrab
|
|
15
15
|
}.merge! options
|
16
16
|
super options
|
17
17
|
|
18
|
-
@object = nil
|
19
18
|
@show_info = false
|
20
|
-
|
19
|
+
|
21
20
|
@frame = vertical padding: 4, background_color: Color.rgb(0, 0, 150), width: 440, height: 112
|
22
21
|
|
22
|
+
@scenario_panel = ScenarioPanel.new state
|
23
|
+
self.object = nil
|
24
|
+
|
23
25
|
self.x, self.y = ($window.width - width) / 2, $window.height - height
|
24
26
|
end
|
25
27
|
|
26
28
|
def object=(object)
|
27
|
-
return if @object == object
|
28
|
-
|
29
|
+
return if defined? @object and object == @object
|
30
|
+
|
31
|
+
@frame.each(&:finalize)
|
29
32
|
|
30
33
|
@frame.clear
|
31
34
|
case object
|
@@ -16,7 +16,7 @@ module SmashAndGrab
|
|
16
16
|
@portrait = image_frame @object.image, padding: 0, background_color: Color::GRAY,
|
17
17
|
factor: (@object.is_a?(Objects::Vehicle) ? 0.25 : 1)
|
18
18
|
|
19
|
-
@object.subscribe :changed do
|
19
|
+
@changed_event = @object.subscribe :changed do
|
20
20
|
@portrait.image = @object.image
|
21
21
|
end
|
22
22
|
end
|
@@ -27,11 +27,15 @@ module SmashAndGrab
|
|
27
27
|
Fidgit::Vertical.new padding: 0, spacing: 0 do
|
28
28
|
scroll_window width: 350, height: 72 do
|
29
29
|
text_area text: "#{@object.name} once was a pomegranate, but it got better... " * 10,
|
30
|
-
background_color: Color::NONE, width: 330, font_height: 14
|
30
|
+
background_color: Color::NONE, width: 330, font_height: 14, editable: false
|
31
31
|
end
|
32
32
|
end
|
33
33
|
end
|
34
34
|
end
|
35
|
+
|
36
|
+
def finalize
|
37
|
+
@changed_event.unsubscribe
|
38
|
+
end
|
35
39
|
end
|
36
40
|
end
|
37
41
|
end
|
@@ -6,7 +6,7 @@ class ActionHistory < Fidgit::History
|
|
6
6
|
|
7
7
|
def_delegators :@actions, :empty?
|
8
8
|
|
9
|
-
def completed_turns; @actions.count {|a| a.is_a?
|
9
|
+
def completed_turns; @actions.count {|a| a.is_a? GameActions::EndTurn }; end
|
10
10
|
|
11
11
|
# Perform a History::Action, adding it to the history.
|
12
12
|
# If there are currently any actions that have been undone, they will be permanently lost and cannot be redone.
|
data/lib/smash_and_grab/main.rb
CHANGED
@@ -39,11 +39,15 @@ require 'syck' # Required for unknown reason, when ocraed!
|
|
39
39
|
require 'gosu'
|
40
40
|
require_folder('gosu_ext', %w[font])
|
41
41
|
|
42
|
+
require 'r18n-desktop'
|
43
|
+
R18n.from_env File.join(EXTRACT_PATH, 'config/lang'), Gosu.language
|
44
|
+
|
42
45
|
require 'chingu'
|
46
|
+
require_folder("chingu_ext", %w[basic_game_object])
|
43
47
|
|
44
48
|
require 'fidgit'
|
45
49
|
Fidgit::Element.schema.merge_schema! YAML.load(File.read(File.expand_path('config/gui/schema.yml', EXTRACT_PATH)))
|
46
|
-
require_folder("fidgit_ext", %w[
|
50
|
+
require_folder("fidgit_ext", %w[element container cursor])
|
47
51
|
|
48
52
|
require 'texplay'
|
49
53
|
require_folder('texplay_ext', %w[color image window])
|
@@ -72,7 +76,7 @@ require_folder("map", %w[tile wall map])
|
|
72
76
|
require_folder("objects", %w[static entity vehicle])
|
73
77
|
require_folder("gui", %w[minimap editor_selector entity_summary info_panel])
|
74
78
|
require_folder("states", %w[edit_level play_level main_menu])
|
75
|
-
require_folder("players", %w[
|
79
|
+
require_folder("players", %w[ai human remote])
|
76
80
|
require_folder("history", %w[editor_action_history game_action_history])
|
77
81
|
|
78
82
|
SmashAndGrab::Log.log.debug { "Scripts loaded in #{"%.3f" % (Time.now - t)} s" }
|
@@ -80,7 +84,7 @@ SmashAndGrab::Log.log.debug { "Scripts loaded in #{"%.3f" % (Time.now - t)} s" }
|
|
80
84
|
t = Time.now
|
81
85
|
SmashAndGrab::GameWindow.new
|
82
86
|
SmashAndGrab::Log.log.debug { "Window created in #{"%.3f" % (Time.now - t)} s" }
|
83
|
-
|
87
|
+
SmashAndGrab:: FONT_NAME = "UnmaskedBB.ttf"
|
84
88
|
unless defined? Ocra or defined? Bacon
|
85
89
|
SmashAndGrab::Log.log.info { "Game window opened" }
|
86
90
|
$window.show
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module SmashAndGrab
|
2
2
|
module Factions
|
3
|
-
class Faction
|
3
|
+
class Faction < BasicGameObject
|
4
4
|
include Fidgit::Event
|
5
5
|
extend Forwardable
|
6
6
|
include Log
|
@@ -15,18 +15,26 @@ module Factions
|
|
15
15
|
|
16
16
|
def friend?(faction); faction.is_a? self.class; end
|
17
17
|
def enemy?(faction); not friend?(faction); end
|
18
|
-
def to_s;
|
19
|
-
def minimap_color; self.class::
|
18
|
+
def to_s; name; end
|
19
|
+
def minimap_color; self.class::MINIMAP_COLOR; end
|
20
20
|
def active?; @active; end
|
21
21
|
def inactive?; !@active; end
|
22
|
+
def colorized_name; self.class::TEXT_COLOR.colorize name; end
|
23
|
+
def name; Inflector.demodulize self.class.name; end
|
22
24
|
|
23
|
-
def initialize
|
24
|
-
|
25
|
+
def initialize
|
26
|
+
super
|
27
|
+
|
28
|
+
@map = nil
|
25
29
|
@entities = []
|
26
30
|
@active = false
|
27
31
|
@player = nil
|
28
32
|
end
|
29
33
|
|
34
|
+
def map=(map)
|
35
|
+
@map = map
|
36
|
+
end
|
37
|
+
|
30
38
|
def <<(entity)
|
31
39
|
@entities << entity
|
32
40
|
end
|
@@ -37,15 +45,22 @@ module Factions
|
|
37
45
|
|
38
46
|
# Start of first turn of the game.
|
39
47
|
def start_game
|
48
|
+
raise unless @map
|
40
49
|
start_turn
|
41
50
|
end
|
42
51
|
|
43
52
|
# Restart from a loaded position.
|
44
53
|
def resume_game
|
54
|
+
raise unless @map
|
45
55
|
@active = true
|
46
56
|
end
|
47
57
|
|
48
58
|
def start_turn
|
59
|
+
parent.publish :game_heading, "=== Turn #{map.turn + 1} ==="
|
60
|
+
parent.publish :game_info, ""
|
61
|
+
parent.publish :game_heading, self.class::TEXT_COLOR.colorize("#{name}' turn (#{Inflector.demodulize player.class})")
|
62
|
+
parent.publish :game_info, ""
|
63
|
+
|
49
64
|
log.info "#{self} started turn #{@map.turn + 1}"
|
50
65
|
@active = true
|
51
66
|
@entities.each(&:start_turn)
|
@@ -65,18 +80,21 @@ module Factions
|
|
65
80
|
|
66
81
|
# Super-villains
|
67
82
|
class Baddies < Faction
|
68
|
-
|
83
|
+
TEXT_COLOR = Color.rgb(255, 0, 0)
|
84
|
+
MINIMAP_COLOR = Color.rgb(255, 50, 50)
|
69
85
|
end
|
70
86
|
|
71
87
|
# Superheroes, police, g-men, etc.
|
72
88
|
class Goodies < Faction
|
73
|
-
|
89
|
+
TEXT_COLOR = Color.rgb(100, 100, 255)
|
90
|
+
MINIMAP_COLOR = Color.rgb(100, 100, 255)
|
74
91
|
def friend?(faction); (faction.is_a? Bystanders) or super; end
|
75
92
|
end
|
76
93
|
|
77
94
|
# Everyone else (NPCS).
|
78
95
|
class Bystanders < Faction
|
79
|
-
|
96
|
+
TEXT_COLOR = Color.rgb(200, 200, 0)
|
97
|
+
MINIMAP_COLOR = Color.rgb(255, 255, 0)
|
80
98
|
|
81
99
|
def friend?(faction); (faction.is_a? Goodies) or super; end
|
82
100
|
end
|
@@ -36,7 +36,7 @@ class Map
|
|
36
36
|
event :wall_type_changed # The actual type itself changed.
|
37
37
|
|
38
38
|
attr_reader :grid_width, :grid_height, :actions
|
39
|
-
attr_reader :
|
39
|
+
attr_reader :active_faction, :turn, :factions, :world_objects
|
40
40
|
|
41
41
|
def to_rect; Rect.new(0, 0, @grid_width * Tile::WIDTH, @grid_height * Tile::HEIGHT); end
|
42
42
|
|
@@ -45,9 +45,17 @@ class Map
|
|
45
45
|
def busy?; factions.any? {|f| f.entities.any?(&:busy?) }; end
|
46
46
|
|
47
47
|
# tile_classes: Nested arrays of Tile class names (Tile::Grass is represented as "Grass")
|
48
|
-
def initialize(data)
|
48
|
+
def initialize(data, factions, options = {})
|
49
|
+
options = {
|
50
|
+
start: true,
|
51
|
+
}.merge! options
|
52
|
+
|
49
53
|
t = Time.now
|
50
54
|
|
55
|
+
raise unless factions.inspect unless factions.size >= 3
|
56
|
+
@factions = factions
|
57
|
+
@factions.each {|f| f.map = self }
|
58
|
+
|
51
59
|
@effects = []
|
52
60
|
@world_objects = []
|
53
61
|
@drawable_objects = []
|
@@ -79,12 +87,6 @@ class Map
|
|
79
87
|
Wall.new self, wall_data
|
80
88
|
end
|
81
89
|
|
82
|
-
@goodies = Factions::Goodies.new self
|
83
|
-
@baddies = Factions::Baddies.new self
|
84
|
-
@bystanders = Factions::Bystanders.new self
|
85
|
-
|
86
|
-
@factions = [@baddies, @goodies, @bystanders] # And order of play.
|
87
|
-
|
88
90
|
data[:objects].each do |object_data|
|
89
91
|
case object_data[:class]
|
90
92
|
when Objects::Entity::CLASS
|
@@ -109,10 +111,12 @@ class Map
|
|
109
111
|
|
110
112
|
record
|
111
113
|
|
112
|
-
if
|
113
|
-
|
114
|
-
|
115
|
-
|
114
|
+
if options[:start]
|
115
|
+
if @actions.empty?
|
116
|
+
start_game
|
117
|
+
else
|
118
|
+
resume_game
|
119
|
+
end
|
116
120
|
end
|
117
121
|
|
118
122
|
# Ensure that if any tiles are changed, that the map is redrawn.
|
@@ -135,6 +139,11 @@ class Map
|
|
135
139
|
end
|
136
140
|
|
137
141
|
def start_game
|
142
|
+
# Ensure that everyone is at max health when scenario helps (not more or less).
|
143
|
+
@factions.each do |faction|
|
144
|
+
faction.entities.each {|e| e.start_game }
|
145
|
+
end
|
146
|
+
|
138
147
|
@active_faction.start_game
|
139
148
|
end
|
140
149
|
|
@@ -4,6 +4,18 @@ class Tile < GameObject
|
|
4
4
|
|
5
5
|
WIDTH, HEIGHT = 32, 16
|
6
6
|
|
7
|
+
# X
|
8
|
+
# / \
|
9
|
+
# X T X <- this tile
|
10
|
+
# \ / <- covered by any wall here
|
11
|
+
# X
|
12
|
+
# / \ <- covered by wall height 1+ here
|
13
|
+
# X X
|
14
|
+
# \ / <- covered by wall height 1+ here
|
15
|
+
# X
|
16
|
+
# X
|
17
|
+
# / \ <- covered by wall height 2+ here
|
18
|
+
#
|
7
19
|
# x, y, direction to cause occlusion.
|
8
20
|
WALL_OCCLUSION_POSITIONS = [
|
9
21
|
[[ 0, 0], :left],
|
@@ -31,7 +43,7 @@ class Tile < GameObject
|
|
31
43
|
class << self
|
32
44
|
def blank; @sprites[0]; end
|
33
45
|
def config; @config ||= YAML.load_file(File.expand_path("config/map/tiles.yml", EXTRACT_PATH)); end
|
34
|
-
def sprites; @sprites ||= SpriteSheet
|
46
|
+
def sprites; @sprites ||= SpriteSheet["floor_tiles.png", WIDTH, HEIGHT, 4]; end
|
35
47
|
end
|
36
48
|
|
37
49
|
attr_reader :entities_exerting_zoc
|
@@ -52,6 +64,14 @@ class Tile < GameObject
|
|
52
64
|
@entities_exerting_zoc = Set.new
|
53
65
|
end
|
54
66
|
|
67
|
+
def overwatched?(faction_targeted)
|
68
|
+
return false unless empty?
|
69
|
+
|
70
|
+
map.factions.any? do |faction|
|
71
|
+
faction.enemy?(faction_targeted) and faction.entities.any? {|e| e.overwatch? self }
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
55
75
|
def entities_exerting_zoc(faction)
|
56
76
|
@entities_exerting_zoc.select {|e| e.action? and e.faction.enemy? faction }
|
57
77
|
end
|
@@ -165,16 +185,23 @@ class Tile < GameObject
|
|
165
185
|
@walls[direction] = wall
|
166
186
|
end
|
167
187
|
|
188
|
+
# Returns wall in this direction.
|
168
189
|
def wall(direction)
|
169
190
|
@walls[direction]
|
170
191
|
end
|
171
192
|
|
193
|
+
# @return [Wall, nil] wall between this and other tile.
|
194
|
+
def wall_to(tile)
|
195
|
+
@walls[direction_to(tile)]
|
196
|
+
end
|
197
|
+
|
198
|
+
# @return [Symbol, nil] Direction to another tile
|
172
199
|
def direction_to(tile)
|
173
200
|
@walls.each_pair do |direction, wall|
|
174
201
|
return direction if wall.destination(self) == tile
|
175
202
|
end
|
176
203
|
|
177
|
-
|
204
|
+
nil
|
178
205
|
end
|
179
206
|
|
180
207
|
def to_json(*a)
|
@@ -34,7 +34,7 @@ class Wall < GameObject
|
|
34
34
|
|
35
35
|
class << self
|
36
36
|
def config; @config ||= YAML.load_file(File.expand_path("config/map/walls.yml", EXTRACT_PATH)); end
|
37
|
-
def sprites; @sprites ||= SpriteSheet
|
37
|
+
def sprites; @sprites ||= SpriteSheet["walls.png", SPRITE_WIDTH, SPRITE_HEIGHT, 8]; end
|
38
38
|
end
|
39
39
|
|
40
40
|
def initialize(map, data)
|
@@ -124,7 +124,7 @@ class Wall < GameObject
|
|
124
124
|
end
|
125
125
|
|
126
126
|
def destination(from)
|
127
|
-
|
127
|
+
@destinations[from]
|
128
128
|
end
|
129
129
|
|
130
130
|
def draw
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module SmashAndGrab
|
2
|
+
module Mixins
|
3
|
+
module HasContents
|
4
|
+
attr_reader :contents
|
5
|
+
|
6
|
+
def setup_contents
|
7
|
+
# @tmp_contents_id was just a holder until we could do this; can't get it to work unless
|
8
|
+
# all objects have been loaded.
|
9
|
+
@contents = @tmp_contents_id ? map.object_by_id(@tmp_contents_id) : nil
|
10
|
+
log.debug { "#{self} started carrying #{@contents}"} if @contents
|
11
|
+
@tmp_contents_id = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def pick_up?(object)
|
15
|
+
@contents.nil? and object.pick_up?(self)
|
16
|
+
end
|
17
|
+
|
18
|
+
def pick_up(object)
|
19
|
+
raise if @contents
|
20
|
+
object.tile = nil
|
21
|
+
@contents = object
|
22
|
+
parent.publish :game_info, "#{colorized_name} picked up #{object.colorized_name}"
|
23
|
+
publish :changed
|
24
|
+
nil
|
25
|
+
end
|
26
|
+
|
27
|
+
def drop(tile)
|
28
|
+
raise unless @contents
|
29
|
+
object = @contents
|
30
|
+
@contents = nil
|
31
|
+
parent.publish :game_info, "#{colorized_name} dropped #{object.colorized_name}"
|
32
|
+
object.tile = tile
|
33
|
+
publish :changed
|
34
|
+
nil
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|