gamefic-standard 2.0.0
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.
- checksums.yaml +7 -0
- data/.gitignore +13 -0
- data/.rspec +2 -0
- data/.travis.yml +7 -0
- data/.vscode/launch.json +20 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +60 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/gamefic-standard.gemspec +44 -0
- data/lib/gamefic-standard.rb +10 -0
- data/lib/gamefic-standard/actions.rb +13 -0
- data/lib/gamefic-standard/actions/drop.rb +21 -0
- data/lib/gamefic-standard/actions/enter.rb +21 -0
- data/lib/gamefic-standard/actions/go.rb +56 -0
- data/lib/gamefic-standard/actions/insert.rb +38 -0
- data/lib/gamefic-standard/actions/inventory.rb +11 -0
- data/lib/gamefic-standard/actions/leave.rb +32 -0
- data/lib/gamefic-standard/actions/look.rb +117 -0
- data/lib/gamefic-standard/actions/nil.rb +38 -0
- data/lib/gamefic-standard/actions/place.rb +43 -0
- data/lib/gamefic-standard/actions/quit.rb +14 -0
- data/lib/gamefic-standard/actions/take.rb +33 -0
- data/lib/gamefic-standard/actions/talk.rb +29 -0
- data/lib/gamefic-standard/actions/wait.rb +5 -0
- data/lib/gamefic-standard/articles.rb +50 -0
- data/lib/gamefic-standard/clothing.rb +4 -0
- data/lib/gamefic-standard/clothing/actions.rb +4 -0
- data/lib/gamefic-standard/clothing/actions/doff.rb +14 -0
- data/lib/gamefic-standard/clothing/actions/drop.rb +10 -0
- data/lib/gamefic-standard/clothing/actions/inventory.rb +16 -0
- data/lib/gamefic-standard/clothing/actions/wear.rb +22 -0
- data/lib/gamefic-standard/clothing/entities.rb +7 -0
- data/lib/gamefic-standard/clothing/entities/clothing.rb +5 -0
- data/lib/gamefic-standard/clothing/entities/coat.rb +3 -0
- data/lib/gamefic-standard/clothing/entities/gloves.rb +3 -0
- data/lib/gamefic-standard/clothing/entities/hat.rb +3 -0
- data/lib/gamefic-standard/clothing/entities/pants.rb +3 -0
- data/lib/gamefic-standard/clothing/entities/shirt.rb +3 -0
- data/lib/gamefic-standard/clothing/entities/shoes.rb +3 -0
- data/lib/gamefic-standard/container.rb +27 -0
- data/lib/gamefic-standard/direction.rb +55 -0
- data/lib/gamefic-standard/edible.rb +23 -0
- data/lib/gamefic-standard/entities.rb +10 -0
- data/lib/gamefic-standard/entities/character.rb +11 -0
- data/lib/gamefic-standard/entities/fixture.rb +3 -0
- data/lib/gamefic-standard/entities/item.rb +5 -0
- data/lib/gamefic-standard/entities/portal.rb +44 -0
- data/lib/gamefic-standard/entities/receptacle.rb +3 -0
- data/lib/gamefic-standard/entities/room.rb +79 -0
- data/lib/gamefic-standard/entities/rubble.rb +11 -0
- data/lib/gamefic-standard/entities/scenery.rb +7 -0
- data/lib/gamefic-standard/entities/supporter.rb +7 -0
- data/lib/gamefic-standard/entities/thing.rb +72 -0
- data/lib/gamefic-standard/give.rb +27 -0
- data/lib/gamefic-standard/grammar.rb +2 -0
- data/lib/gamefic-standard/grammar/attributes.rb +37 -0
- data/lib/gamefic-standard/grammar/pronoun.rb +101 -0
- data/lib/gamefic-standard/lockable.rb +93 -0
- data/lib/gamefic-standard/modules.rb +7 -0
- data/lib/gamefic-standard/modules/enterable.rb +19 -0
- data/lib/gamefic-standard/modules/use.rb +45 -0
- data/lib/gamefic-standard/openable.rb +49 -0
- data/lib/gamefic-standard/pathfinder.rb +65 -0
- data/lib/gamefic-standard/queries.rb +25 -0
- data/lib/gamefic-standard/test.rb +36 -0
- data/lib/gamefic-standard/version.rb +5 -0
- metadata +182 -0
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'gamefic-standard/entities/thing'
|
2
|
+
require 'gamefic-standard/entities/character'
|
3
|
+
require 'gamefic-standard/entities/fixture'
|
4
|
+
require 'gamefic-standard/entities/item'
|
5
|
+
require 'gamefic-standard/entities/portal'
|
6
|
+
require 'gamefic-standard/entities/receptacle'
|
7
|
+
require 'gamefic-standard/entities/room'
|
8
|
+
require 'gamefic-standard/entities/scenery'
|
9
|
+
require 'gamefic-standard/entities/rubble'
|
10
|
+
require 'gamefic-standard/entities/supporter'
|
@@ -0,0 +1,44 @@
|
|
1
|
+
class Portal < Thing
|
2
|
+
attr_accessor :destination
|
3
|
+
|
4
|
+
# Find the portal in the destination that returns to this portal's parent
|
5
|
+
#
|
6
|
+
# @return [Room]
|
7
|
+
def find_reverse
|
8
|
+
return nil if destination.nil?
|
9
|
+
rev = direction.reverse
|
10
|
+
if rev != nil
|
11
|
+
destination.children.that_are(Portal).each { |c|
|
12
|
+
if c.direction == rev
|
13
|
+
return c
|
14
|
+
end
|
15
|
+
}
|
16
|
+
end
|
17
|
+
nil
|
18
|
+
end
|
19
|
+
|
20
|
+
# Get the ordinal direction of this Portal
|
21
|
+
# Portals have distinct direction and name properties so games can display a
|
22
|
+
# bare compass direction for exits, e.g., "south" vs. "the southern door."
|
23
|
+
#
|
24
|
+
# @return [Direction]
|
25
|
+
def direction
|
26
|
+
@direction
|
27
|
+
end
|
28
|
+
|
29
|
+
def direction= d
|
30
|
+
@direction = Direction.find(d)
|
31
|
+
end
|
32
|
+
|
33
|
+
def name
|
34
|
+
@name || (direction.nil? ? destination.name : direction.name)
|
35
|
+
end
|
36
|
+
|
37
|
+
def instruction
|
38
|
+
direction || (destination ? "to #{destination.definitely}" : name)
|
39
|
+
end
|
40
|
+
|
41
|
+
def synonyms
|
42
|
+
"#{super} #{@destination} #{@direction} #{!direction.nil? ? direction.synonyms : ''}"
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
class Room < Thing
|
2
|
+
attr_writer :explicit_exits
|
3
|
+
|
4
|
+
set_default explicit_exits: true
|
5
|
+
|
6
|
+
def explicit_exits?
|
7
|
+
@explicit_exits
|
8
|
+
end
|
9
|
+
|
10
|
+
def synonyms
|
11
|
+
@synonyms.to_s + " around here room"
|
12
|
+
end
|
13
|
+
|
14
|
+
def tell(message)
|
15
|
+
children.each { |c|
|
16
|
+
c.tell message
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
def find_portal(direction)
|
21
|
+
d = direction.to_s
|
22
|
+
portals = children.that_are(Portal).delete_if { |p| p.direction.to_s != d }
|
23
|
+
portals[0]
|
24
|
+
end
|
25
|
+
|
26
|
+
class << self
|
27
|
+
def explicit_exits?
|
28
|
+
default_attributes[:explicit_exits]
|
29
|
+
end
|
30
|
+
|
31
|
+
def explicit_exits=(bool)
|
32
|
+
set_default explicit_exits: bool
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# @todo Monkey patching might not be the best way to handle this. It's only
|
38
|
+
# necessary because of specs that make Plot#connect calls. Consider
|
39
|
+
# changing the specs instead.
|
40
|
+
module Gamefic::World
|
41
|
+
# Create portals between rooms.
|
42
|
+
#
|
43
|
+
# @return [Portal]
|
44
|
+
def connect origin, destination, direction = nil, type: Portal, two_way: true
|
45
|
+
if direction.nil?
|
46
|
+
portal = make type, :parent => origin, :destination => destination
|
47
|
+
if two_way == true
|
48
|
+
portal2 = make type, :parent => destination, :destination => origin
|
49
|
+
end
|
50
|
+
else
|
51
|
+
if direction.kind_of?(String)
|
52
|
+
direction = Direction.find(direction)
|
53
|
+
end
|
54
|
+
portal = make type, :direction => direction, :parent => origin, :destination => destination
|
55
|
+
portal.proper_named = true if type == Portal
|
56
|
+
if two_way == true
|
57
|
+
reverse = direction.reverse
|
58
|
+
if reverse == nil
|
59
|
+
raise "#{direction.name.cap_first} does not have an opposite direction"
|
60
|
+
end
|
61
|
+
portal2 = make type, :direction => reverse, :parent => destination, :destination => origin
|
62
|
+
portal2.proper_named = true if type == Portal
|
63
|
+
end
|
64
|
+
end
|
65
|
+
portal
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
Room.module_exec self do |plot|
|
70
|
+
# Define the connect method dynamically so the plot is available
|
71
|
+
define_method :connect do |destination, direction = nil, type: Portal, two_way: true|
|
72
|
+
plot.connect self, destination, direction, type: Portal, two_way: true
|
73
|
+
end
|
74
|
+
end
|
75
|
+
class Room
|
76
|
+
# @!method connect destination, direction = nil, type: Portal, two_way: true
|
77
|
+
# Create a portal to connect this room to a destination.
|
78
|
+
# @return [Portal]
|
79
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# script 'standard/entities/scenery'
|
2
|
+
require 'gamefic-standard/entities/scenery'
|
3
|
+
|
4
|
+
# Rubble is Scenery with slightly modified action responses.
|
5
|
+
# Intended for things that might be portable but are useless.
|
6
|
+
# Rule of thumb: Scenery is something that can't be carried,
|
7
|
+
# like a table or the sky; and Rubble is something that might
|
8
|
+
# be portable but is otherwise useless, like trash or debris.
|
9
|
+
#
|
10
|
+
class Rubble < Scenery
|
11
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
class Thing < Gamefic::Entity
|
2
|
+
include Grammar::Attributes
|
3
|
+
|
4
|
+
attr_writer :itemized
|
5
|
+
|
6
|
+
attr_writer :sticky
|
7
|
+
|
8
|
+
attr_writer :portable
|
9
|
+
|
10
|
+
# An optional description to use when itemizing entities in room
|
11
|
+
# descriptions. The locale_description will be used instead of adding
|
12
|
+
# the entity's name to a list.
|
13
|
+
#
|
14
|
+
attr_accessor :locale_description
|
15
|
+
|
16
|
+
# A message to be displayed in response to DROP actions when the entity is
|
17
|
+
# sticky.
|
18
|
+
#
|
19
|
+
attr_accessor :sticky_message
|
20
|
+
|
21
|
+
set_default itemized: true
|
22
|
+
set_default sticky: false
|
23
|
+
set_default portable: false
|
24
|
+
|
25
|
+
# Itemized entities are automatically listed in room descriptions.
|
26
|
+
#
|
27
|
+
# @return [Boolean]
|
28
|
+
def itemized?
|
29
|
+
@itemized
|
30
|
+
end
|
31
|
+
|
32
|
+
# Sticky entities cannot be dropped with DROP actions
|
33
|
+
#
|
34
|
+
# @return [Boolean]
|
35
|
+
def sticky?
|
36
|
+
@sticky
|
37
|
+
end
|
38
|
+
|
39
|
+
# Portable entities can be taken with TAKE actions.
|
40
|
+
#
|
41
|
+
# @return [Boolean]
|
42
|
+
def portable?
|
43
|
+
@portable
|
44
|
+
end
|
45
|
+
|
46
|
+
# @return [Boolean]
|
47
|
+
def attached?
|
48
|
+
@attached ||= false
|
49
|
+
end
|
50
|
+
|
51
|
+
# @param [Boolean]
|
52
|
+
def attached= bool
|
53
|
+
bool = false if parent.nil?
|
54
|
+
@attached = bool
|
55
|
+
end
|
56
|
+
|
57
|
+
def parent= p
|
58
|
+
self.attached = false unless p == parent
|
59
|
+
super
|
60
|
+
end
|
61
|
+
|
62
|
+
# The entity's parent room (i.e., the closest ascendant that is a Room).
|
63
|
+
#
|
64
|
+
# @return [Room]
|
65
|
+
def room
|
66
|
+
p = parent
|
67
|
+
until p.is_a?(Room) or p.nil?
|
68
|
+
p = p.parent
|
69
|
+
end
|
70
|
+
p
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# @gamefic.script standard/give
|
2
|
+
|
3
|
+
respond :give, Use.available, Gamefic::Query::Children.new do |actor, _character, gift|
|
4
|
+
actor.tell "Nothing happens."
|
5
|
+
end
|
6
|
+
|
7
|
+
respond :give, Use.available(Character), Use.available do |actor, character, gift|
|
8
|
+
if gift.sticky?
|
9
|
+
actor.tell gift.sticky_message || "You need to keep #{the gift} for now."
|
10
|
+
else
|
11
|
+
actor.tell "#{The character} doesn't want #{the gift}."
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
respond :give, Use.available(Character), Use.available do |actor, _character, gift|
|
16
|
+
if gift.parent == actor
|
17
|
+
actor.proceed
|
18
|
+
else
|
19
|
+
actor.tell "You don't have #{the gift}."
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
respond :give, Use.text, Use.available do |actor, character, _gift|
|
24
|
+
actor.tell "You don't see any \"#{character}\" here."
|
25
|
+
end
|
26
|
+
|
27
|
+
interpret "give :gift to :character", "give :character :gift"
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Grammar
|
2
|
+
# A collection of attributes that enable grammar features for entities, such
|
3
|
+
# as selecting their correct pronouns.
|
4
|
+
#
|
5
|
+
module Attributes
|
6
|
+
# @see #gender
|
7
|
+
attr_writer :gender
|
8
|
+
|
9
|
+
# @see #plural?
|
10
|
+
attr_writer :plural
|
11
|
+
|
12
|
+
# The gender of the object. Supported values are :male, :female, :neutral,
|
13
|
+
# and :other. Use :neutral for objects that don't have a gender (i.e.,
|
14
|
+
# "it"). Use :other for people or characters that have an unspecified or
|
15
|
+
# non-binary gender (i.e., "they").
|
16
|
+
#
|
17
|
+
# @return [Symbol]
|
18
|
+
def gender
|
19
|
+
@gender ||= :neutral
|
20
|
+
end
|
21
|
+
|
22
|
+
# True if the object should be referred to in the plural, e.g., "they"
|
23
|
+
# instead of "it."
|
24
|
+
# @return [Boolean]
|
25
|
+
#
|
26
|
+
def plural?
|
27
|
+
@plural ||= false
|
28
|
+
end
|
29
|
+
|
30
|
+
# For now, the object's person is always assumed to be third
|
31
|
+
# (he/she/it/they). A future version of this library might support first
|
32
|
+
# (I/me) and second (you).
|
33
|
+
def person
|
34
|
+
3
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Grammar
|
4
|
+
# Functions to select pronouns based on an entity's attributes, such as
|
5
|
+
# gender.
|
6
|
+
#
|
7
|
+
module Pronoun
|
8
|
+
class << self
|
9
|
+
# @param entity [#person, #plural?, #gender]
|
10
|
+
# @return [String]
|
11
|
+
def subjective(entity)
|
12
|
+
map(entity)[:subjective]
|
13
|
+
end
|
14
|
+
alias they subjective
|
15
|
+
alias he subjective
|
16
|
+
alias she subjective
|
17
|
+
|
18
|
+
# @param entity [#person, #plural?, #gender]
|
19
|
+
# @return [String]
|
20
|
+
def subjective_(entity)
|
21
|
+
subjective(entity).cap_first
|
22
|
+
end
|
23
|
+
alias they_ subjective_
|
24
|
+
alias he_ subjective_
|
25
|
+
alias she_ subjective_
|
26
|
+
|
27
|
+
# @param entity [#person, #plural?, #gender]
|
28
|
+
# @return [String]
|
29
|
+
def objective(entity)
|
30
|
+
map(entity)[:objective]
|
31
|
+
end
|
32
|
+
alias them objective
|
33
|
+
|
34
|
+
# @param entity [#person, #plural?, #gender]
|
35
|
+
# @return [String]
|
36
|
+
def objective_(entity)
|
37
|
+
objective(entity).cap_first
|
38
|
+
end
|
39
|
+
alias them_ objective_
|
40
|
+
|
41
|
+
# @param entity [#person, #plural?, #gender]
|
42
|
+
# @return [String]
|
43
|
+
def possessive(entity)
|
44
|
+
map(entity)[:possessive]
|
45
|
+
end
|
46
|
+
alias their possessive
|
47
|
+
|
48
|
+
# @param entity [#person, #plural?, #gender]
|
49
|
+
# @return [String]
|
50
|
+
def possessive_(entity)
|
51
|
+
possessive(entity).cap_first
|
52
|
+
end
|
53
|
+
alias their_ possessive_
|
54
|
+
|
55
|
+
# @param entity [#person, #plural?, #gender]
|
56
|
+
# @return [String]
|
57
|
+
def reflexive(entity)
|
58
|
+
map(entity)[:reflexive]
|
59
|
+
end
|
60
|
+
alias themselves reflexive
|
61
|
+
alias themself reflexive
|
62
|
+
|
63
|
+
# @param entity [#person, #plural?, #gender]
|
64
|
+
# @return [String]
|
65
|
+
def reflexive_(entity)
|
66
|
+
reflexive(entity).cap_first
|
67
|
+
end
|
68
|
+
alias themselves_ reflexive_
|
69
|
+
alias themself_ reflexive_
|
70
|
+
|
71
|
+
# @param entity [#person, #plural?, #gender]
|
72
|
+
# @return [Hash]
|
73
|
+
def map(entity)
|
74
|
+
plurality = (entity.plural? ? :plural : :singular)
|
75
|
+
maps[[(entity.person || 3), plurality, entity.gender]] ||
|
76
|
+
maps[[(entity.person || 3), plurality]]
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
def maps
|
82
|
+
@maps ||= {
|
83
|
+
[1, :singular] => Hash[map_keys.zip(%w[I me my myself])],
|
84
|
+
[2, :singular] => Hash[map_keys.zip(%w[you you your yourself])],
|
85
|
+
[3, :singular] => Hash[map_keys.zip(%w[it it its itself])],
|
86
|
+
[3, :singular, :male] => Hash[map_keys.zip(%w[he him his himself])],
|
87
|
+
[3, :singular, :female] => Hash[map_keys.zip(%w[she her her herself])],
|
88
|
+
[3, :singular, :other] => Hash[map_keys.zip(%w[they them their themselves])],
|
89
|
+
[3, :singular, :neutral] => Hash[map_keys.zip(%w[it it its itself])],
|
90
|
+
[1, :plural] => Hash[map_keys.zip(%w[we us our ourselves])],
|
91
|
+
[2, :plural] => Hash[map_keys.zip(%w[you you your yourselves])],
|
92
|
+
[3, :plural] => Hash[map_keys.zip(%w[they them their themselves])]
|
93
|
+
}
|
94
|
+
end
|
95
|
+
|
96
|
+
def map_keys
|
97
|
+
@map_keys ||= %i[subjective objective possessive reflexive]
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# @gamefic.script standard/lockable
|
2
|
+
|
3
|
+
require 'gamefic-standard/openable'
|
4
|
+
|
5
|
+
# A module for entities that are both openable and lockable.
|
6
|
+
#
|
7
|
+
module Lockable
|
8
|
+
include Openable
|
9
|
+
|
10
|
+
attr_accessor :lock_key
|
11
|
+
|
12
|
+
def locked=(bool)
|
13
|
+
@locked = bool
|
14
|
+
if @locked == true
|
15
|
+
self.open = false
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def open=(bool)
|
20
|
+
@open = bool
|
21
|
+
@locked = false if @open == true
|
22
|
+
end
|
23
|
+
|
24
|
+
def locked?
|
25
|
+
@locked ||= false
|
26
|
+
end
|
27
|
+
|
28
|
+
def has_lock_key?
|
29
|
+
!@lock_key.nil?
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
Gamefic.script do
|
34
|
+
respond :lock, Use.available do |actor, thing|
|
35
|
+
actor.tell "You can't lock #{the thing}."
|
36
|
+
end
|
37
|
+
|
38
|
+
respond :_toggle_lock, Use.available(Lockable, :has_lock_key?) do |actor, thing|
|
39
|
+
verb = thing.locked? ? 'unlock' : 'lock'
|
40
|
+
key = nil
|
41
|
+
if thing.lock_key.parent == actor
|
42
|
+
key = thing.lock_key
|
43
|
+
end
|
44
|
+
if key.nil?
|
45
|
+
actor.tell "You don't have any way to #{verb} #{the thing}."
|
46
|
+
else
|
47
|
+
actor.tell "You #{verb} #{the thing} with #{the key}."
|
48
|
+
thing.locked = !thing.locked?
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
respond :lock, Use.available(Lockable, :has_lock_key?), Use.children do |actor, thing, key|
|
53
|
+
if thing.lock_key == key
|
54
|
+
actor.perform :_toggle_lock, thing
|
55
|
+
else
|
56
|
+
actor.tell "You can't unlock #{the thing} with #{the key}."
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
respond :lock, Use.available(Lockable, :has_lock_key?), Use.available do |actor, thing, key|
|
61
|
+
actor.perform :take, key if key.parent != actor
|
62
|
+
actor.proceed if key.parent == actor
|
63
|
+
end
|
64
|
+
|
65
|
+
respond :unlock, Use.available do |actor, thing|
|
66
|
+
actor.tell "You can't unlock #{the thing}."
|
67
|
+
end
|
68
|
+
|
69
|
+
respond :unlock, Use.available(Lockable, :has_lock_key?), Use.children do |actor, thing, key|
|
70
|
+
if thing.lock_key == key
|
71
|
+
actor.perform :_toggle_lock, thing
|
72
|
+
else
|
73
|
+
actor.tell "You can't unlock #{the thing} with #{the key}."
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
respond :unlock, Use.available(Lockable, :has_lock_key?), Use.available do |actor, thing, key|
|
78
|
+
actor.perform :take, key if key.parent != actor
|
79
|
+
actor.proceed if key.parent == actor
|
80
|
+
end
|
81
|
+
|
82
|
+
respond :open, Use.available(Lockable) do |actor, thing|
|
83
|
+
if thing.locked?
|
84
|
+
actor.tell "#{The thing} is locked."
|
85
|
+
else
|
86
|
+
actor.proceed
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
interpret "lock :container with :key", "lock :container :key"
|
91
|
+
interpret "unlock :container with :key", "unlock :container :key"
|
92
|
+
interpret "open :container with :key", "unlock :container :key"
|
93
|
+
end
|