twisty 0.0.2b → 0.0.3
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 +4 -4
- data/lib/twisty/command.rb +35 -3
- data/lib/twisty/engine.rb +129 -8
- data/lib/twisty/entity.rb +17 -1
- data/lib/twisty/error.rb +8 -0
- data/lib/twisty/item.rb +105 -3
- data/lib/twisty/room.rb +125 -72
- data/lib/twisty.rb +15 -15
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0c4b41c7bfe9c7ccc8ab8bda55ee1564de9d5940
|
4
|
+
data.tar.gz: 07135ce28c624d6b8d41dd5bd5cfd67d48764544
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f9d9c48f2101a4aac3c01ed9c1c46b72608901289675d577f8696ccf7d0370e3320d40b7b18eb003f8ab8a02d234d7d1910c0b33c7017fea2c809f4af91754de
|
7
|
+
data.tar.gz: e68e5797a78c4bde6598087cd5e091b7b7840ef89acf420f3be863770036a1ad18ffd00f10603ebf2b72d6bc9a999cc8cdf1334f7dab0896d996dbfca778ac7e
|
data/lib/twisty/command.rb
CHANGED
@@ -7,17 +7,49 @@
|
|
7
7
|
# #
|
8
8
|
#############################################################################
|
9
9
|
|
10
|
+
require_relative 'engine.rb'
|
11
|
+
|
10
12
|
require 'rtype'
|
11
13
|
|
12
14
|
module Twisty
|
13
15
|
|
16
|
+
#Used to provide the descriptions, examples of and executable code of commands
|
17
|
+
#that the player can type.
|
14
18
|
class Command
|
15
|
-
|
16
|
-
|
19
|
+
#(+String+) An example of the command e.g. "take item"
|
20
|
+
attr_reader :help1
|
21
|
+
#(+String+) Short description of what the command actually does
|
22
|
+
attr_reader :help2
|
23
|
+
|
24
|
+
#Initialiser. Use Engine.define_command() instead
|
25
|
+
#
|
26
|
+
#help1:: (+String+) An example of the command e.g. "take item"
|
27
|
+
#help2:: (+String+) Short description of what the command actually does
|
28
|
+
#func:: (Proc) Code that provides the commands effect(s). *NOTE* This
|
29
|
+
# must take exactly one argument of type +Array+[+String+]
|
17
30
|
def initialize(help1, help2, func)
|
18
31
|
@help1 = help1
|
19
32
|
@help2 = help2
|
20
|
-
|
33
|
+
|
34
|
+
self.define_singleton_method(:exec, func)
|
35
|
+
end
|
36
|
+
|
37
|
+
#Executes this instance of command. This is redefined on a per-instance
|
38
|
+
#basis by Command.new().
|
39
|
+
#
|
40
|
+
#args:: (+Array+[+String+]) Words the player typed in
|
41
|
+
def exec(args)
|
42
|
+
return
|
43
|
+
end
|
44
|
+
|
45
|
+
protected
|
46
|
+
#(+Engine+)
|
47
|
+
#
|
48
|
+
#Convinience class so that each instances version of Command.exec() does
|
49
|
+
#not need to contain
|
50
|
+
# engine = Engine.instance
|
51
|
+
def engine
|
52
|
+
Twisty::Engine.instance()
|
21
53
|
end
|
22
54
|
end
|
23
55
|
|
data/lib/twisty/engine.rb
CHANGED
@@ -17,11 +17,20 @@ require_relative 'room.rb'
|
|
17
17
|
|
18
18
|
module Twisty
|
19
19
|
|
20
|
+
#Main class within Twisty.
|
20
21
|
class Engine
|
21
22
|
include Singleton
|
22
23
|
|
23
|
-
|
24
|
+
#(+Hash+{+Symbol+ => +Item+}) All Items in the game regardless of if
|
25
|
+
#they have been placed anywhere
|
26
|
+
attr_reader :items
|
27
|
+
#(+Hash+{+Symbol+ => +Room+}) All Rooms in the game regardless of if
|
28
|
+
#they can be reached
|
29
|
+
attr_reader :rooms
|
30
|
+
#(+Array+[+Symbol+]) Keys of the Items the player is carrying
|
31
|
+
attr_reader :inventory
|
24
32
|
|
33
|
+
#Initialiser. As this class is a singleton use Engine.instance instead
|
25
34
|
def initialize
|
26
35
|
@items = {}
|
27
36
|
@rooms = {}
|
@@ -31,7 +40,7 @@ class Engine
|
|
31
40
|
|
32
41
|
@playing = nil
|
33
42
|
|
34
|
-
@commands = {} #Filled in lib/twisty.rb
|
43
|
+
@commands = {} #Filled in by lib/twisty.rb
|
35
44
|
end
|
36
45
|
|
37
46
|
################################
|
@@ -41,6 +50,21 @@ class Engine
|
|
41
50
|
# TODO: Make private "defining" method
|
42
51
|
|
43
52
|
rtype [Symbol, String, String, Hash] => nil
|
53
|
+
#Creates a new instance of Item in Engine.items indexed by id. Use this
|
54
|
+
#instead of Item.new().
|
55
|
+
#
|
56
|
+
#id:: (+Symbol+) Key within Engine.items
|
57
|
+
#name:: Name shown in "look" and used to "take" / "drop" the Item.
|
58
|
+
# *NOTE* This MUST be a single word.
|
59
|
+
#desc:: (+String+) Long description shown when the player uses "look at"
|
60
|
+
#options:: (+Hash+{+Symbol+ => +Any}) Additional attributes of the Item
|
61
|
+
#
|
62
|
+
# At present there are only two valid options that can be
|
63
|
+
# passed via options:
|
64
|
+
# fixed:: (+Boolean+) If set to true prevents "take" from
|
65
|
+
# working on the Item. Set to +false+ by default
|
66
|
+
# storage:: (+Integer+) Indicates the number of other Items
|
67
|
+
# that this Item can contain. Set to +0+ by default
|
44
68
|
def define_item(id, name, desc, options={})
|
45
69
|
options = {fixed: false, storage: 0}.merge(options)
|
46
70
|
|
@@ -57,6 +81,13 @@ class Engine
|
|
57
81
|
end
|
58
82
|
|
59
83
|
rtype [Symbol, String, String] => nil
|
84
|
+
#Creates a new instance of Room in Engine.rooms indexed by id. Use this
|
85
|
+
#instead of Room.new().
|
86
|
+
#
|
87
|
+
#id:: (+Symbol+) Key for the Room in Engine.rooms
|
88
|
+
#name:: String (preferably one word) shown in the prompt when the player
|
89
|
+
# is located in this Room
|
90
|
+
#desc:: (+String+) The long description of the player's current location
|
60
91
|
def define_room(id, name, desc)
|
61
92
|
room = Twisty::Room.new(id, name, desc)
|
62
93
|
|
@@ -75,6 +106,14 @@ class Engine
|
|
75
106
|
end
|
76
107
|
|
77
108
|
rtype [Symbol, Symbol, String] => nil
|
109
|
+
#Creates an exit from one Room to another
|
110
|
+
#
|
111
|
+
#from:: (+Symbol+) Key for the Room where the player is before using
|
112
|
+
# "walk"
|
113
|
+
#to:: (+Symbol+) Key for the Room where the player is after using "walk"
|
114
|
+
#name:: (+String+) Used to name the _door_. This can be a word such as
|
115
|
+
# "East" rather than the name of the destination. *NOTE* Must be
|
116
|
+
# one word
|
78
117
|
def add_door(from, to, name)
|
79
118
|
if @rooms.has_key?(from)
|
80
119
|
if @rooms.has_key?(to)
|
@@ -90,6 +129,11 @@ class Engine
|
|
90
129
|
end
|
91
130
|
|
92
131
|
rtype [Symbol] => nil
|
132
|
+
#Change the the room that the player is currently in to the one
|
133
|
+
#represented by the Symbol id. Unlike Engine.goto() This does not print
|
134
|
+
#any information or trigger events.
|
135
|
+
#
|
136
|
+
#id:: (+Symbol+) Key of the Room where the player will go to
|
93
137
|
def current_room=(id)
|
94
138
|
if @rooms.has_key? id
|
95
139
|
@current_room = id
|
@@ -101,6 +145,12 @@ class Engine
|
|
101
145
|
end
|
102
146
|
|
103
147
|
rtype [] => nil
|
148
|
+
#Place an Item represented by the Symbol id. Unlike
|
149
|
+
#Engine.take_item_by_id() this does not remove the Item from any Room it
|
150
|
+
#may be in or trigger any events.
|
151
|
+
#
|
152
|
+
#id:: (+Symbol+) Key of the Item that will be added to the player's
|
153
|
+
# inventory
|
104
154
|
def give(id)
|
105
155
|
if @items.include? id
|
106
156
|
@inventory << id
|
@@ -112,6 +162,16 @@ class Engine
|
|
112
162
|
end
|
113
163
|
|
114
164
|
rtype [Regexp, String, String, Proc] => nil
|
165
|
+
#Create a new command for the user to type. Not applicable for creating
|
166
|
+
#methods to develop the game with
|
167
|
+
#
|
168
|
+
#pattern:: (+Regexp+) Pattern that triggers the command to be run.
|
169
|
+
#*NOTE* Must be unique and unambigious
|
170
|
+
#help1:: (+String+) An example of the command. E.g. "take item"
|
171
|
+
#help2:: (+String+) A short description of what the command does
|
172
|
+
#&func:: (+Proc+) Code executed when the player types the command in.
|
173
|
+
# *NOTE* Must take one argument of type +Array+[+String+] which
|
174
|
+
# contains what the player typed
|
115
175
|
def define_command(pattern, help1, help2, &func)
|
116
176
|
@commands[pattern] = Command.new(help1, help2, func)
|
117
177
|
return nil
|
@@ -122,21 +182,34 @@ class Engine
|
|
122
182
|
#########################
|
123
183
|
|
124
184
|
rtype [] => Room
|
185
|
+
#(+Room+)
|
186
|
+
#
|
187
|
+
#The instance of Room that the player is currently in
|
125
188
|
def current_room
|
126
189
|
@rooms[@current_room]
|
127
190
|
end
|
128
191
|
|
129
192
|
rtype [] => Hash.of(Symbol, String)
|
193
|
+
#(+Hash+{+Symbol+ => +String+})
|
194
|
+
#
|
195
|
+
#Exits of the Room the player is currently in
|
130
196
|
def current_doors
|
131
197
|
@rooms[@current_room].doors
|
132
198
|
end
|
133
199
|
|
134
200
|
rtype [] => Array.of(Symbol)
|
201
|
+
#(+Array+[+Symbol+])
|
202
|
+
#
|
203
|
+
#Keys of the Items present in the Room where the player is currently
|
204
|
+
#located
|
135
205
|
def current_items
|
136
206
|
@rooms[@current_room].items
|
137
207
|
end
|
138
208
|
|
139
209
|
rtype [] => Array.of(Symbol)
|
210
|
+
#(+Array+[+Symbol+])
|
211
|
+
#
|
212
|
+
#Items that the user is currently carrying
|
140
213
|
def inventory
|
141
214
|
@inventory
|
142
215
|
end
|
@@ -145,6 +218,9 @@ class Engine
|
|
145
218
|
# Game play commands #
|
146
219
|
##########################
|
147
220
|
rtype [String] => nil
|
221
|
+
#The "take item" command. Probably best not to call directly
|
222
|
+
#
|
223
|
+
#name:: (+String+) Name of an Item the player has typed in
|
148
224
|
def take_item_by_name(name)
|
149
225
|
current_items.each do |id|
|
150
226
|
if @items.has_key? id
|
@@ -163,6 +239,11 @@ class Engine
|
|
163
239
|
end
|
164
240
|
|
165
241
|
rtype [Symbol] => nil
|
242
|
+
#Called by Engine.take_item_by_name. Probably best not to call directly
|
243
|
+
#
|
244
|
+
#id:: (+Symbol+) Index entry for the Item to be removed from the current
|
245
|
+
# room and placed in the player's inventory as found by
|
246
|
+
# Engine.take_item_by_name()
|
166
247
|
def take_item_by_id(id)
|
167
248
|
if @items.has_key? id
|
168
249
|
if current_items.include? id
|
@@ -187,6 +268,12 @@ class Engine
|
|
187
268
|
end
|
188
269
|
|
189
270
|
rtype [String, String] => nil
|
271
|
+
#The "take item from item" command. Probably best not to call directly
|
272
|
+
#
|
273
|
+
#item:: (+String+) Name that the player has typed for an item to be
|
274
|
+
# inventory
|
275
|
+
#container:: (+String+) Name of an Item that the player is looking to
|
276
|
+
# remove added to the another Item from
|
190
277
|
def take_from_by_name_name(item, container)
|
191
278
|
current_items.each do |id|
|
192
279
|
if @items[id].name.downcase == container
|
@@ -200,6 +287,12 @@ class Engine
|
|
200
287
|
end
|
201
288
|
|
202
289
|
rtype [String, Symbol] => nil
|
290
|
+
#Called by take_from_by_name_name. Probably best not to call directly.
|
291
|
+
#
|
292
|
+
#item:: (+String+) Name that the player has typed for an item to be
|
293
|
+
# added to the inventory
|
294
|
+
#container:: (+Symbol+) Key for the containing Item as found by
|
295
|
+
# Engine.take_from_by_name_name
|
203
296
|
def take_from_by_name_id(item, container)
|
204
297
|
@items[container].contents.each do |id|
|
205
298
|
if @items[id].name.downcase == item
|
@@ -218,6 +311,10 @@ class Engine
|
|
218
311
|
end
|
219
312
|
|
220
313
|
rtype [String, String] => nil
|
314
|
+
#The "put item in item" command. Probably best not to call directly
|
315
|
+
#
|
316
|
+
#item:: (+String+) Name that the player has typed for an item to be
|
317
|
+
# added to a container
|
221
318
|
def put_item_by_name_name(item, container)
|
222
319
|
@inventory.each do |id|
|
223
320
|
if @items[id].name.downcase == item
|
@@ -231,6 +328,13 @@ class Engine
|
|
231
328
|
end
|
232
329
|
|
233
330
|
rtype [Symbol, String] => nil
|
331
|
+
#Called by Engine.put_item_by_name_name. Probably best not to call
|
332
|
+
#directly
|
333
|
+
#
|
334
|
+
#item:: (+Symbol+) Key in Engine.items of the item to be placed in the
|
335
|
+
# container as found by Engine.put_item_by_name_name
|
336
|
+
#container:: (+String+) Name that the player has typed for the Item
|
337
|
+
# to act as a container
|
234
338
|
def put_item_by_id_name(item, container)
|
235
339
|
current_items.each do |id|
|
236
340
|
if @items[id].name.downcase == container
|
@@ -253,6 +357,10 @@ class Engine
|
|
253
357
|
end
|
254
358
|
|
255
359
|
rtype [String] => nil
|
360
|
+
#The "drop item" command. Probably best not to call directly
|
361
|
+
#
|
362
|
+
#name:: (+String+) The name, typed by the player, of the item to be
|
363
|
+
#dropped
|
256
364
|
def drop_item_by_name(name)
|
257
365
|
@inventory.each do |id|
|
258
366
|
if @items.has_key? id
|
@@ -272,6 +380,10 @@ class Engine
|
|
272
380
|
end
|
273
381
|
|
274
382
|
rtype [Symbol] => nil
|
383
|
+
#Called by Engine.drop_item_by_name. Probably best not to call directly
|
384
|
+
#
|
385
|
+
#id:: (+Symbol+) Key in Engine.items of the item to be dropped as found
|
386
|
+
#by Engine.drop_item_by_name
|
275
387
|
def drop_item_by_id(id)
|
276
388
|
if @items.has_key? id
|
277
389
|
if @items[id].drop_event
|
@@ -286,12 +398,17 @@ class Engine
|
|
286
398
|
end
|
287
399
|
|
288
400
|
rtype [Symbol] => nil
|
401
|
+
#Called by the "walk door" command. Unlike current_room=(id) this
|
402
|
+
#triggers events and only moves the player if said events run
|
403
|
+
#successfully
|
404
|
+
#
|
405
|
+
#id:: (+Symbol+) Key in Engine.rooms of the Room that the player will
|
406
|
+
# be moved to
|
289
407
|
def goto(to)
|
290
408
|
if @rooms.has_key? to
|
291
409
|
if current_room.exit_event and @rooms[to].enter_event
|
292
410
|
@current_room = to
|
293
411
|
end
|
294
|
-
puts current_room.name
|
295
412
|
else
|
296
413
|
raise TwistyError.new "Room #{to} has not been defined"
|
297
414
|
end
|
@@ -304,15 +421,18 @@ class Engine
|
|
304
421
|
#######################
|
305
422
|
|
306
423
|
rtype [] => nil
|
424
|
+
#Starts the main loop of the game
|
425
|
+
#
|
426
|
+
#*NOTE* This must be included once and only once at the end of the
|
427
|
+
#program
|
307
428
|
def start_loop
|
308
429
|
@playing = true
|
309
430
|
|
310
|
-
puts current_room.name
|
311
|
-
puts
|
312
431
|
current_room.look
|
432
|
+
puts
|
313
433
|
|
314
434
|
while @playing == true
|
315
|
-
printf "> "
|
435
|
+
printf "#{current_room.name} > "
|
316
436
|
begin
|
317
437
|
line = gets
|
318
438
|
if line.class == NilClass
|
@@ -329,12 +449,14 @@ class Engine
|
|
329
449
|
end
|
330
450
|
|
331
451
|
rtype [] => nil
|
452
|
+
#Ends the main loop of the game. Use this for win and loose conditions
|
332
453
|
def end_loop
|
333
454
|
@playing = false
|
334
455
|
return nil
|
335
456
|
end
|
336
457
|
|
337
458
|
rtype [] => nil
|
459
|
+
#Called by start_loop to process user inpu.
|
338
460
|
def parse(line)
|
339
461
|
#Strip double spaces and downcase
|
340
462
|
tokens = line.downcase.split
|
@@ -342,8 +464,7 @@ class Engine
|
|
342
464
|
|
343
465
|
@commands.each do |pattern, command|
|
344
466
|
if line =~ pattern
|
345
|
-
|
346
|
-
instance_exec(tokens, &command.func)
|
467
|
+
command.exec(tokens)
|
347
468
|
return nil
|
348
469
|
end
|
349
470
|
end
|
data/lib/twisty/entity.rb
CHANGED
@@ -9,12 +9,26 @@
|
|
9
9
|
|
10
10
|
require 'rtype'
|
11
11
|
|
12
|
+
#Author:: Ryan McCoskrie (mailto:work@ryanmccoskrie.me)
|
13
|
+
#Copyright:: Copyright (c) 2017 - 2018 RyanMcCoskrie
|
14
|
+
#License:: MIT public license
|
15
|
+
|
12
16
|
module Twisty
|
13
17
|
|
18
|
+
#Super-class of Room and Item. Do not use directly.
|
19
|
+
#
|
20
|
+
#*NOTE* It is possible this class may be removed in future versions.
|
14
21
|
class Entity
|
22
|
+
#(+Symbol+)The Symbol used to distinguish the Entity from other memebers
|
23
|
+
#of the same sub-class
|
15
24
|
attr_reader :id
|
16
25
|
|
17
26
|
rtype [Entity] => Boolean
|
27
|
+
#(+Boolean+)
|
28
|
+
#
|
29
|
+
#Checks if two different instances of Entity refer to the same datum
|
30
|
+
#
|
31
|
+
#other:: (+Entity+) instance of Entity to check for equality against
|
18
32
|
def ==(other)
|
19
33
|
if other.class == self.class
|
20
34
|
return other.id == @id
|
@@ -25,7 +39,9 @@ class Entity
|
|
25
39
|
end
|
26
40
|
end
|
27
41
|
|
28
|
-
|
42
|
+
#(+Engine+)
|
43
|
+
#
|
44
|
+
#Convinience class to access the Engine
|
29
45
|
def engine
|
30
46
|
return Engine.instance()
|
31
47
|
end
|
data/lib/twisty/error.rb
CHANGED
@@ -9,16 +9,24 @@
|
|
9
9
|
|
10
10
|
module Twisty
|
11
11
|
|
12
|
+
#Super-class of GameError and PlayError. Do not use directly
|
12
13
|
class TwistyError < RuntimeError
|
14
|
+
#(+String+) Message detailing the exception
|
13
15
|
attr_reader :message
|
14
16
|
|
17
|
+
#Initialiser
|
18
|
+
#
|
19
|
+
#s:: (+String+) Contents of TwistyError.message
|
15
20
|
def initialize(s)
|
16
21
|
@message = s
|
17
22
|
end
|
18
23
|
end
|
19
24
|
|
25
|
+
#Used when Twisty has found a bug in a specific game
|
20
26
|
class GameError < TwistyError
|
21
27
|
end
|
28
|
+
|
29
|
+
#Used to tell the player when (s)he has used a command incorrectly
|
22
30
|
class PlayError < TwistyError
|
23
31
|
end
|
24
32
|
|
data/lib/twisty/item.rb
CHANGED
@@ -12,11 +12,34 @@ require_relative 'entity'
|
|
12
12
|
require 'rtype'
|
13
13
|
|
14
14
|
|
15
|
+
#Author:: Ryan McCoskrie (mailto:work@ryanmccoskrie.me)
|
16
|
+
#Copyright:: Copyright (c) 2017 - 2018 RyanMcCoskrie
|
17
|
+
#License:: MIT public license
|
18
|
+
|
15
19
|
module Twisty
|
16
20
|
|
21
|
+
# This class models objects that (movable and otherwise) that the character
|
22
|
+
# can interact with.
|
17
23
|
class Item < Entity
|
18
|
-
|
19
|
-
|
24
|
+
#(+String+) One-word name of the Item
|
25
|
+
attr_reader :name
|
26
|
+
#(+String+) Description printed when the Item is looked at.
|
27
|
+
attr_reader :desc
|
28
|
+
#(+Boolean+) Indicates if the Item can not be moved
|
29
|
+
attr_reader :fixed
|
30
|
+
#(+Integer+) Number of other Items this instance can store
|
31
|
+
attr_reader :storage
|
32
|
+
#(+Array+[+Symbol+]) Other Item this instance is currently storiing
|
33
|
+
attr_reader :contents
|
34
|
+
|
35
|
+
#Initialiser. Please use Engine.define_item() instead
|
36
|
+
#
|
37
|
+
#id:: (+Symbol+) Key in Engine.items of the Item
|
38
|
+
#name:: (+String+) One-word name of the Item
|
39
|
+
#desc:: A long description of the Item printed when the player uses
|
40
|
+
# "look at item"
|
41
|
+
#fixed:: (+Boolean+) If set to +false+ the Item can not be taken
|
42
|
+
#storage:: (+Integer+) The number of other Items this instance can hold
|
20
43
|
def initialize(id, name, desc, fixed, storage)
|
21
44
|
@id = id
|
22
45
|
@name = name
|
@@ -27,16 +50,52 @@ class Item < Entity
|
|
27
50
|
end
|
28
51
|
|
29
52
|
rtype [] => Boolean
|
53
|
+
#(+Boolean+)
|
54
|
+
#
|
55
|
+
#Executed when the Item is picked up. This function can be redefined
|
56
|
+
#on a per-instance basis using on_take(&block). If this returns false
|
57
|
+
#take will fail
|
30
58
|
def take_event
|
59
|
+
puts "Taken"
|
31
60
|
return true
|
32
61
|
end
|
33
62
|
|
34
63
|
rtype [] => Boolean
|
64
|
+
#(+Boolean+)
|
65
|
+
#
|
66
|
+
#Executed when the Item is picked up. This function can be redefined
|
67
|
+
#on a per-instance basis using on_drop(&block). If this returns false
|
68
|
+
#drop will fail.
|
35
69
|
def drop_event
|
70
|
+
puts "Dropped"
|
36
71
|
return true
|
37
72
|
end
|
38
73
|
|
74
|
+
rtype [Symbol] => Boolean
|
75
|
+
#(+Boolean+)
|
76
|
+
#
|
77
|
+
#Executed when another Item is placed inside this instance. This
|
78
|
+
#function can be redefined on a per-instance basis using on_add(&block).
|
79
|
+
#If this return false add_item will fail
|
80
|
+
#
|
81
|
+
#item:: (+Symbol+) Key in Engine.items of the item being added
|
82
|
+
def put_content_event(item)
|
83
|
+
return true
|
84
|
+
end
|
85
|
+
|
86
|
+
rtype [Symbol] => Boolean
|
87
|
+
#(+Boolean+)
|
88
|
+
#
|
89
|
+
#Executed an Item inside this instance of Item is removed by the player.
|
90
|
+
#If this returns false "take X from Y" will fail.
|
91
|
+
#
|
92
|
+
#item:: (+Symbol+) Key in Engine.items of the item being taken
|
93
|
+
def take_content_event(item)
|
94
|
+
puts "Taken"
|
95
|
+
end
|
96
|
+
|
39
97
|
rtype [] => nil
|
98
|
+
#Prints the description and the names of the contents if applicable
|
40
99
|
def look
|
41
100
|
puts @desc
|
42
101
|
|
@@ -54,12 +113,20 @@ class Item < Entity
|
|
54
113
|
end
|
55
114
|
|
56
115
|
rtype [Symbol] => Boolean
|
116
|
+
#(+Boolean+)
|
117
|
+
#
|
118
|
+
#Returns +true+ if this item contains another represented by the symbol
|
119
|
+
#item
|
57
120
|
def contains_item?(item)
|
58
121
|
return @contents.include?(item) if @storage > 0
|
59
|
-
return false
|
60
122
|
end
|
61
123
|
|
62
124
|
rtype [Symbol] => nil
|
125
|
+
#Stores another Item represented by the Symbol item and stores it
|
126
|
+
#within this Item if:
|
127
|
+
# * storage > 0
|
128
|
+
# * contents.size < 0
|
129
|
+
# * insert_event() returns true
|
63
130
|
def add_item(item)
|
64
131
|
if @storage == 0
|
65
132
|
raise GameError.new "#{@id} is not a container"
|
@@ -74,6 +141,11 @@ class Item < Entity
|
|
74
141
|
end
|
75
142
|
|
76
143
|
rtype [Symbol] => nil
|
144
|
+
#Removes an Item contained within this instance
|
145
|
+
#*NOTE* This does not place the Item in the player's inventory
|
146
|
+
#
|
147
|
+
#item:: (+Symbol+) Key in Engine.items of the Item being placed in this
|
148
|
+
# instance of Item
|
77
149
|
def del_item(item)
|
78
150
|
#Skip if already contained
|
79
151
|
if contains_item?(item)
|
@@ -84,16 +156,46 @@ class Item < Entity
|
|
84
156
|
end
|
85
157
|
|
86
158
|
rtype [Proc] => nil
|
159
|
+
#Redefines Item::take_event for this specific instance
|
160
|
+
#
|
161
|
+
#&block:: (+Proc+ => +Boolean+) The new version of Item.take_event for
|
162
|
+
# this specific instance *NOTE* Must return a +Boolean+
|
87
163
|
def on_take(&block)
|
88
164
|
self.define_singleton_method(:take_event, &block)
|
89
165
|
return nil
|
90
166
|
end
|
91
167
|
|
92
168
|
rtype [Proc] => nil
|
169
|
+
#Redefines Item::drop_event for this specific instance
|
170
|
+
#
|
171
|
+
#&block:: (+Proc+ => +Boolean+) The new version of Item.drop_event for
|
172
|
+
# this specific instance *NOTE* Must return a +Boolean+
|
93
173
|
def on_drop(&block)
|
94
174
|
self.define_singleton_method(:drop_event, &block)
|
95
175
|
return nil
|
96
176
|
end
|
177
|
+
|
178
|
+
rtype [Proc] => nil
|
179
|
+
#Redefines Item::put_content_event for this specific instance
|
180
|
+
#
|
181
|
+
#&block:: (+Proc+ => +Boolean+) The new version of
|
182
|
+
# Item.put_content_event for this specific instance.
|
183
|
+
# *NOTE* Must return a +Boolean+
|
184
|
+
def on_put_content(&block)
|
185
|
+
self.define_singleton_method(:put_content_event, &block)
|
186
|
+
return nil
|
187
|
+
end
|
188
|
+
|
189
|
+
rtype [Proc] => nil
|
190
|
+
#Redefines Item::take_content_event for this specific instance
|
191
|
+
#
|
192
|
+
#&block:: (+Proc+ => +Boolean+) The new version of
|
193
|
+
# Item.take_content_event for this specific instance.
|
194
|
+
# *NOTE* Must return a +Boolean+
|
195
|
+
def on_put_content(&block)
|
196
|
+
self.define_singleton_method(:put_content_event, &block)
|
197
|
+
return nil
|
198
|
+
end
|
97
199
|
end
|
98
200
|
|
99
201
|
end
|
data/lib/twisty/room.rb
CHANGED
@@ -11,96 +11,149 @@ require_relative 'entity.rb'
|
|
11
11
|
|
12
12
|
require 'rtype'
|
13
13
|
|
14
|
+
#Author:: Ryan McCoskrie (mailto:work@ryanmccoskrie.me)
|
15
|
+
#Copyright:: Copyright (c) 2017 - 2018 RyanMcCoskrie
|
16
|
+
#License:: MIT public license
|
17
|
+
|
14
18
|
module Twisty
|
15
19
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
20
|
+
#This class models the locations within the game.
|
21
|
+
class Room < Entity
|
22
|
+
#(+String+) Short name shown in the prompt
|
23
|
+
attr_reader :name
|
24
|
+
#(+String+) Description printed when the player types "look"
|
25
|
+
attr_reader :desc
|
26
|
+
#(+Hash+{+String+ => +Symbol+}) Names and keys in Engine.rooms of the
|
27
|
+
#locations the player can move from
|
28
|
+
attr_reader :doors
|
29
|
+
#(+Array+[+String+]) Items in the room. Does not include Items stored
|
30
|
+
#inside other Items
|
31
|
+
attr_accessor :items
|
32
|
+
|
33
|
+
rtype [Symbol, String, String] => Array
|
34
|
+
#Initializer. Please use Twisty::Engine::define_room() instead.
|
35
|
+
#
|
36
|
+
#id:: (+Symbol+) that represents the Room in Engine.rooms()
|
37
|
+
#name:: (+String+) Name shown to the player in the prompt
|
38
|
+
#desc:: (+String+) Long description shown when the player types "look"
|
39
|
+
def initialize(id, name, desc)
|
40
|
+
@id = id
|
41
|
+
@name = name
|
42
|
+
@desc = desc
|
43
|
+
@doors = {}
|
44
|
+
@items = []
|
45
|
+
end
|
28
46
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
47
|
+
rtype [] => Boolean
|
48
|
+
#(+Boolean+)
|
49
|
+
#
|
50
|
+
#Executed when the player attempts to enter the Room. This can be
|
51
|
+
#redefined on a per-instance basis using Room.on_enter(&block). If this
|
52
|
+
#returns +false+ the player will be blocked from entering
|
53
|
+
def enter_event
|
54
|
+
return true
|
55
|
+
end
|
33
56
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
57
|
+
rtype [] => Boolean
|
58
|
+
#(+Boolean+)
|
59
|
+
#
|
60
|
+
#Executed when the player attempts to exit the Room. This can be
|
61
|
+
#redefined on a per-instance basis using on_exit(&block). If this
|
62
|
+
#returns +false+ the player will be blocked from exiting
|
63
|
+
def exit_event
|
64
|
+
return true
|
65
|
+
end
|
38
66
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
67
|
+
rtype [Symbol, String] => nil
|
68
|
+
#Adds an exit from this room to another
|
69
|
+
#*NOTE* For most purposes Engine.add_door() would be more convinient
|
70
|
+
#*NOTE* The "door" only works in one direction and that the exit is
|
71
|
+
#referred to by the String name, not the name of the other Room.
|
72
|
+
#
|
73
|
+
#to:: (+Symbol+) Key in Engine.rooms of the location the player will
|
74
|
+
# be moved to if "walk" is sucessfully executed
|
75
|
+
#name:: (+String+) Name displayed by "look" and typed as part of "walk".
|
76
|
+
# This can be a word such as "East" instead of the destination's
|
77
|
+
# actual name
|
78
|
+
def add_door(to, name)
|
79
|
+
if name.split().length != 1
|
80
|
+
raise GameError.new "Door name must be one word"
|
81
|
+
elsif @doors.has_key? name
|
82
|
+
raise GameError.new "Door with name #{name} already exist in #{@id}"
|
83
|
+
else
|
84
|
+
@doors[to] = name
|
50
85
|
end
|
51
86
|
|
52
|
-
|
53
|
-
|
54
|
-
if @items.include? id
|
55
|
-
raise GameError.new "Duplicate item in room #{@id}"
|
56
|
-
else
|
57
|
-
@items << id
|
58
|
-
end
|
59
|
-
end
|
87
|
+
return nil
|
88
|
+
end
|
60
89
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
90
|
+
rtype [Symbol] => Array.of(Symbol)
|
91
|
+
#Places an Item within a the Room. Note that is must first be defined
|
92
|
+
#with Twisty::Engine::define_item()
|
93
|
+
#
|
94
|
+
#id:: (+Symbol+) Key in Engine.items for the Item that will be added to
|
95
|
+
# the Room
|
96
|
+
def add_item(id)
|
97
|
+
if @items.include? id
|
98
|
+
raise GameError.new "Duplicate item in room #{@id}"
|
99
|
+
else
|
100
|
+
@items << id
|
65
101
|
end
|
102
|
+
end
|
66
103
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
104
|
+
rtype [Proc] => nil
|
105
|
+
#Used to redefine enter_event
|
106
|
+
#
|
107
|
+
#&block:: (+Proc+ => +Boolean+) Code executed on entering the Room.
|
108
|
+
# *NOTE* If this returns +false+ the player "walk" will fail
|
109
|
+
def on_enter(&block)
|
110
|
+
self.define_singleton_method(:enter_event, &block)
|
111
|
+
return nil
|
112
|
+
end
|
72
113
|
|
73
|
-
|
74
|
-
|
75
|
-
|
114
|
+
rtype [Proc] => nil
|
115
|
+
#Used to redefine exit_event
|
116
|
+
#
|
117
|
+
#&block:: (+Proc+ => +Boolean+) Code executed on exiting the Room.
|
118
|
+
# *NOTE* If this returns +false+ the player "walk" will fail
|
119
|
+
def on_exit(&block)
|
120
|
+
self.define_singleton_method(:exit_event, &block)
|
121
|
+
return nil
|
122
|
+
end
|
76
123
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
124
|
+
rtype [] => nil
|
125
|
+
#Prints the description of the Room and its contents / exits if
|
126
|
+
#applicable.
|
127
|
+
def look
|
128
|
+
puts @desc
|
81
129
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
130
|
+
if @items.length == 0
|
131
|
+
puts "Nothing is located here"
|
132
|
+
elsif @items.length == 1
|
133
|
+
puts
|
86
134
|
|
87
|
-
|
88
|
-
|
89
|
-
|
135
|
+
puts "Located here is:"
|
136
|
+
puts engine.items[@items[0]].name
|
137
|
+
else
|
138
|
+
puts
|
90
139
|
|
91
|
-
|
140
|
+
puts "Located here are:"
|
141
|
+
@items.each{ |id| puts engine.items[id].name }
|
142
|
+
end
|
92
143
|
|
93
|
-
|
94
|
-
puts "There is no exit"
|
95
|
-
elsif doors.length == 1
|
96
|
-
puts "The only exit is: #{@doors.values[0]}"
|
97
|
-
else
|
98
|
-
puts "The exits are:"
|
99
|
-
@doors.values.each{|name| puts name}
|
100
|
-
end
|
144
|
+
puts
|
101
145
|
|
102
|
-
|
146
|
+
if doors.length == 0
|
147
|
+
puts "There is no exit"
|
148
|
+
elsif doors.length == 1
|
149
|
+
puts "The only exit is: #{@doors.values[0]}"
|
150
|
+
else
|
151
|
+
puts "The exits are:"
|
152
|
+
@doors.values.each{|name| puts name}
|
103
153
|
end
|
154
|
+
|
155
|
+
return nil
|
104
156
|
end
|
157
|
+
end
|
105
158
|
|
106
159
|
end
|
data/lib/twisty.rb
CHANGED
@@ -21,7 +21,7 @@ Engine.instance.define_command(
|
|
21
21
|
/^help$/,
|
22
22
|
"help",
|
23
23
|
"Write out the list of commands you are reading now") do |x|
|
24
|
-
|
24
|
+
engine.commands.values.each do |command|
|
25
25
|
puts "#{command.help1}:"
|
26
26
|
puts "#{command.help2}"
|
27
27
|
puts
|
@@ -30,67 +30,67 @@ Engine.instance.define_command(
|
|
30
30
|
Engine.instance.define_command(
|
31
31
|
/^look$/,
|
32
32
|
"look",
|
33
|
-
"Look at the current room") {|x| current_room.look()}
|
33
|
+
"Look at the current room") {|x| engine.current_room.look()}
|
34
34
|
|
35
35
|
Engine.instance.define_command(
|
36
36
|
/^look at \w+$/,
|
37
37
|
"look at object",
|
38
38
|
"Look at a specific object") do |tokens|
|
39
39
|
found = false
|
40
|
-
current_items.each do |id|
|
41
|
-
if
|
42
|
-
|
40
|
+
engine.current_items.each do |id|
|
41
|
+
if engine.items[id].name.downcase == tokens[2]
|
42
|
+
engine.items[id].look
|
43
43
|
found = true
|
44
44
|
break
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
48
48
|
#Error condidtion
|
49
|
-
raise PlayError.new "I see no #{tokens[2]}"
|
49
|
+
raise PlayError.new "I see no #{tokens[2]}" if not found
|
50
50
|
end
|
51
51
|
Engine.instance.define_command(
|
52
52
|
/^inventory$/,
|
53
53
|
"inventory",
|
54
54
|
"Get a list of things you are carrying") do |x|
|
55
|
-
if
|
55
|
+
if engine.inventory.size == 0
|
56
56
|
puts "You are currently carrying nothing"
|
57
57
|
else
|
58
58
|
puts "You are currently carring: "
|
59
|
-
|
59
|
+
engine.inventory.each{|id| puts engine.items[id].name}
|
60
60
|
end
|
61
61
|
end
|
62
62
|
Engine.instance.define_command(
|
63
63
|
/^take \w+$/,
|
64
64
|
"take object",
|
65
65
|
"Take an object and carry it in your inventory") do |tokens|
|
66
|
-
take_item_by_name(tokens[1])
|
66
|
+
engine.take_item_by_name(tokens[1])
|
67
67
|
end
|
68
68
|
Engine.instance.define_command(
|
69
69
|
/^take \w+ from \w+$/,
|
70
70
|
"take object from container",
|
71
71
|
"Take an object out of a container and carry it your inventory") do |tokens|
|
72
|
-
take_from_by_name_name(tokens[1], tokens[3])
|
72
|
+
engine.take_from_by_name_name(tokens[1], tokens[3])
|
73
73
|
end
|
74
74
|
Engine.instance.define_command(
|
75
75
|
/^drop \w+$/,
|
76
76
|
"drop object",
|
77
77
|
"Remove an object from your inventory and leave it in the room") do |tokens|
|
78
|
-
drop_item_by_name(tokens[1])
|
78
|
+
engine.drop_item_by_name(tokens[1])
|
79
79
|
end
|
80
80
|
Engine.instance.define_command(
|
81
81
|
/^put \w+ in \w+$/,
|
82
82
|
"put item in container",
|
83
83
|
"Remove an object from your inventory and leave it in a container") do |tokens|
|
84
|
-
put_item_by_name_name(tokens[1], tokens[3])
|
84
|
+
engine.put_item_by_name_name(tokens[1], tokens[3])
|
85
85
|
end
|
86
86
|
Engine.instance.define_command(
|
87
87
|
/^walk \w+$/,
|
88
88
|
"walk exit",
|
89
89
|
"Walk out of the room through an exit") do |tokens|
|
90
90
|
found = false
|
91
|
-
current_doors.each_pair do |to, name|
|
91
|
+
engine.current_doors.each_pair do |to, name|
|
92
92
|
if name.downcase == tokens[1]
|
93
|
-
goto to
|
93
|
+
engine.goto to
|
94
94
|
found = true
|
95
95
|
break
|
96
96
|
end
|
@@ -102,5 +102,5 @@ Engine.instance.define_command(
|
|
102
102
|
Engine.instance.define_command(
|
103
103
|
/^quit$/,
|
104
104
|
"quit",
|
105
|
-
"Stop playing the game") {|x|
|
105
|
+
"Stop playing the game") {|x| engine.end_loop()}
|
106
106
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: twisty
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryan McCoskrie
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-02-
|
11
|
+
date: 2018-02-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rtype-native
|
@@ -37,7 +37,7 @@ files:
|
|
37
37
|
- lib/twisty/error.rb
|
38
38
|
- lib/twisty/item.rb
|
39
39
|
- lib/twisty/room.rb
|
40
|
-
homepage: http://
|
40
|
+
homepage: http://gitlab.com/RyanMcCoskrie/Twisty
|
41
41
|
licenses:
|
42
42
|
- MIT
|
43
43
|
metadata: {}
|
@@ -52,12 +52,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
52
52
|
version: '0'
|
53
53
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
54
|
requirements:
|
55
|
-
- - "
|
55
|
+
- - ">="
|
56
56
|
- !ruby/object:Gem::Version
|
57
|
-
version:
|
57
|
+
version: '0'
|
58
58
|
requirements: []
|
59
59
|
rubyforge_project:
|
60
|
-
rubygems_version: 2.
|
60
|
+
rubygems_version: 2.5.2.1
|
61
61
|
signing_key:
|
62
62
|
specification_version: 4
|
63
63
|
summary: Twisty
|