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
@@ -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
|