twisty 0.0.2b

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 973c95d14cceffd3e604a89a4d3e13aa78668c79
4
+ data.tar.gz: 2890e7f27a04df943e73b0052b4bafeae65ef3a7
5
+ SHA512:
6
+ metadata.gz: fcfbb0a47cc2baf7acb9e6c78999a96ed4e0b5ed50d0684ba0786faba2e7d529bbd500501db262eac72533483951c66be4c69593b67639669f5d553758f9f1ff
7
+ data.tar.gz: 91cef32321c07af3e9c27f0d6a31f625703de54ca1a8a4b706ff0a0e443a29a9619dd2b96c96533461d82aa3fc6bb049c8aea456bf6934fb6f330e1616fbfebd
@@ -0,0 +1,24 @@
1
+ #############################################################################
2
+ # #
3
+ # Copyright (c) 2017, Ryan McCoskrie <work@ryanmccoskrie.me> #
4
+ # #
5
+ # This software is distributed under the MIT License which can be found #
6
+ # in the root directory. #
7
+ # #
8
+ #############################################################################
9
+
10
+ require 'rtype'
11
+
12
+ module Twisty
13
+
14
+ class Command
15
+ rtype_accessor :help1, :help2, String
16
+ rtype_accessor :func, Proc
17
+ def initialize(help1, help2, func)
18
+ @help1 = help1
19
+ @help2 = help2
20
+ @func = func
21
+ end
22
+ end
23
+
24
+ end
@@ -0,0 +1,359 @@
1
+ #############################################################################
2
+ # #
3
+ # Copyright (c) 2017, Ryan McCoskrie <work@ryanmccoskrie.me> #
4
+ # #
5
+ # This software is distributed under the MIT License which can be found #
6
+ # in the root directory. #
7
+ # #
8
+ #############################################################################
9
+
10
+ require 'singleton'
11
+ require 'rtype'
12
+
13
+ require_relative 'error.rb'
14
+ require_relative 'command.rb'
15
+ require_relative 'item.rb'
16
+ require_relative 'room.rb'
17
+
18
+ module Twisty
19
+
20
+ class Engine
21
+ include Singleton
22
+
23
+ attr_reader :items, :rooms, :inventory
24
+
25
+ def initialize
26
+ @items = {}
27
+ @rooms = {}
28
+
29
+ @current_room = nil
30
+ @inventory = []
31
+
32
+ @playing = nil
33
+
34
+ @commands = {} #Filled in lib/twisty.rb
35
+ end
36
+
37
+ ################################
38
+ # Game definition commands #
39
+ ################################
40
+
41
+ # TODO: Make private "defining" method
42
+
43
+ rtype [Symbol, String, String, Hash] => nil
44
+ def define_item(id, name, desc, options={})
45
+ options = {fixed: false, storage: 0}.merge(options)
46
+
47
+ fixed = options[:fixed] || false
48
+ storage = options[:storage] || 0
49
+
50
+ if @items[id] == nil
51
+ @items[id] = Twisty::Item.new(id, name, desc, fixed, storage)
52
+ else
53
+ raise GameError.new "Item #{id} has already been defined"
54
+ end
55
+
56
+ return nil
57
+ end
58
+
59
+ rtype [Symbol, String, String] => nil
60
+ def define_room(id, name, desc)
61
+ room = Twisty::Room.new(id, name, desc)
62
+
63
+ if @rooms[id] == nil
64
+ @rooms[id] = room
65
+ else
66
+ raise GameError.new "Room #{id} has already been defined"
67
+ end
68
+
69
+ #First defined room is default starting point
70
+ if @rooms.size == 1
71
+ @current_room = id
72
+ end
73
+
74
+ return nil
75
+ end
76
+
77
+ rtype [Symbol, Symbol, String] => nil
78
+ def add_door(from, to, name)
79
+ if @rooms.has_key?(from)
80
+ if @rooms.has_key?(to)
81
+ @rooms[from].add_door(to, name)
82
+ else
83
+ raise GameError.new "Invalid room name: #{to}"
84
+ end
85
+ else
86
+ raise GameError.new "Invalid room name: #{from}"
87
+ end
88
+
89
+ return nil
90
+ end
91
+
92
+ rtype [Symbol] => nil
93
+ def current_room=(id)
94
+ if @rooms.has_key? id
95
+ @current_room = id
96
+ else
97
+ raise GameError.new "Room #{id} has not been defined"
98
+ end
99
+
100
+ return nil
101
+ end
102
+
103
+ rtype [] => nil
104
+ def give(id)
105
+ if @items.include? id
106
+ @inventory << id
107
+ else
108
+ raise GameError.new "Invalid item: #{id}"
109
+ end
110
+
111
+ return nil
112
+ end
113
+
114
+ rtype [Regexp, String, String, Proc] => nil
115
+ def define_command(pattern, help1, help2, &func)
116
+ @commands[pattern] = Command.new(help1, help2, func)
117
+ return nil
118
+ end
119
+
120
+ #########################
121
+ # Utility functions #
122
+ #########################
123
+
124
+ rtype [] => Room
125
+ def current_room
126
+ @rooms[@current_room]
127
+ end
128
+
129
+ rtype [] => Hash.of(Symbol, String)
130
+ def current_doors
131
+ @rooms[@current_room].doors
132
+ end
133
+
134
+ rtype [] => Array.of(Symbol)
135
+ def current_items
136
+ @rooms[@current_room].items
137
+ end
138
+
139
+ rtype [] => Array.of(Symbol)
140
+ def inventory
141
+ @inventory
142
+ end
143
+
144
+ ##########################
145
+ # Game play commands #
146
+ ##########################
147
+ rtype [String] => nil
148
+ def take_item_by_name(name)
149
+ current_items.each do |id|
150
+ if @items.has_key? id
151
+ if @items[id].name.downcase == name.downcase
152
+ take_item_by_id(id)
153
+ return nil
154
+ end
155
+ else
156
+ raise GameError.new "Invalid Item #{id} in #{@current_room}"
157
+ end
158
+ end
159
+
160
+ #Implicit error condition
161
+ raise PlayError.new "There is no #{name} here"
162
+ return nil
163
+ end
164
+
165
+ rtype [Symbol] => nil
166
+ def take_item_by_id(id)
167
+ if @items.has_key? id
168
+ if current_items.include? id
169
+ if @items[id].fixed
170
+ raise PlayError.new "You can not move that"
171
+ else
172
+ if @items[id].take_event
173
+ current_room.items.delete id
174
+ @inventory << id
175
+ end
176
+
177
+ return nil
178
+ end
179
+ else
180
+ raise GameError.new "There is no #{id} in #{@current_room}"
181
+ end
182
+ else
183
+ raise GameError.new "Invalid Item #{id} in #{@current_room}"
184
+ end
185
+
186
+ return nil
187
+ end
188
+
189
+ rtype [String, String] => nil
190
+ def take_from_by_name_name(item, container)
191
+ current_items.each do |id|
192
+ if @items[id].name.downcase == container
193
+ return take_from_by_name_id(item, id)
194
+ end
195
+ end
196
+
197
+ #Implicit error
198
+ raise PlayError.new "I can not see any #{container} here"
199
+ return nil
200
+ end
201
+
202
+ rtype [String, Symbol] => nil
203
+ def take_from_by_name_id(item, container)
204
+ @items[container].contents.each do |id|
205
+ if @items[id].name.downcase == item
206
+ if @items[id].take_event
207
+ @items[container].del_item id
208
+ @inventory << id
209
+ end
210
+
211
+ return nil
212
+ end
213
+ end
214
+
215
+ #Implicit Error
216
+ raise PlayError.new "I see no #{item} in the #{@items[container].name}"
217
+ return nil
218
+ end
219
+
220
+ rtype [String, String] => nil
221
+ def put_item_by_name_name(item, container)
222
+ @inventory.each do |id|
223
+ if @items[id].name.downcase == item
224
+ return put_item_by_id_name(id, container)
225
+ end
226
+ end
227
+
228
+ #Implicit Error
229
+ raise PlayError.new "You have no #{item}"
230
+ return nil
231
+ end
232
+
233
+ rtype [Symbol, String] => nil
234
+ def put_item_by_id_name(item, container)
235
+ current_items.each do |id|
236
+ if @items[id].name.downcase == container
237
+ if @items[id].storage == 0
238
+ raise PlayError.new "It won't fit in there"
239
+ end
240
+
241
+ if @items[item].drop_event
242
+ @items[id].add_item(item)
243
+ @inventory.delete item
244
+ end
245
+
246
+ return nil
247
+ end
248
+ end
249
+
250
+ #Implicit Error
251
+ raise PlayError.new "I see no #{item}"
252
+ return nil
253
+ end
254
+
255
+ rtype [String] => nil
256
+ def drop_item_by_name(name)
257
+ @inventory.each do |id|
258
+ if @items.has_key? id
259
+ if @items[id].name.downcase == name
260
+ drop_item_by_id(id)
261
+
262
+ return nil
263
+ end
264
+ else
265
+ raise GameError.new "Invalid Item: #{id}"
266
+ end
267
+ end
268
+
269
+ #Implicit error condition
270
+ raise PlayError.new "You are not carrying that"
271
+ return nil
272
+ end
273
+
274
+ rtype [Symbol] => nil
275
+ def drop_item_by_id(id)
276
+ if @items.has_key? id
277
+ if @items[id].drop_event
278
+ current_room.items << id
279
+ @inventory.delete id
280
+ end
281
+
282
+ return nil
283
+ else
284
+ raise GameError.new "Invalid item: #{id} in inventory"
285
+ end
286
+ end
287
+
288
+ rtype [Symbol] => nil
289
+ def goto(to)
290
+ if @rooms.has_key? to
291
+ if current_room.exit_event and @rooms[to].enter_event
292
+ @current_room = to
293
+ end
294
+ puts current_room.name
295
+ else
296
+ raise TwistyError.new "Room #{to} has not been defined"
297
+ end
298
+
299
+ return nil
300
+ end
301
+
302
+ #######################
303
+ # Loop and Parser #
304
+ #######################
305
+
306
+ rtype [] => nil
307
+ def start_loop
308
+ @playing = true
309
+
310
+ puts current_room.name
311
+ puts
312
+ current_room.look
313
+
314
+ while @playing == true
315
+ printf "> "
316
+ begin
317
+ line = gets
318
+ if line.class == NilClass
319
+ @playing = false
320
+ return nil
321
+ end
322
+ parse(line)
323
+ rescue PlayError => e
324
+ puts e.message
325
+ end
326
+ end
327
+
328
+ return nil
329
+ end
330
+
331
+ rtype [] => nil
332
+ def end_loop
333
+ @playing = false
334
+ return nil
335
+ end
336
+
337
+ rtype [] => nil
338
+ def parse(line)
339
+ #Strip double spaces and downcase
340
+ tokens = line.downcase.split
341
+ line = tokens.join(' ')
342
+
343
+ @commands.each do |pattern, command|
344
+ if line =~ pattern
345
+ #Execute as if a member function
346
+ instance_exec(tokens, &command.func)
347
+ return nil
348
+ end
349
+ end
350
+
351
+ #Implicit error
352
+ raise PlayError.new "I don't know how to #{line}"
353
+
354
+ #Never reached
355
+ return nil
356
+ end
357
+ end
358
+
359
+ end
@@ -0,0 +1,34 @@
1
+ #############################################################################
2
+ # #
3
+ # Copyright (c) 2017, Ryan McCoskrie <work@ryanmccoskrie.me> #
4
+ # #
5
+ # This software is distributed under the MIT License which can be found #
6
+ # in the root directory. #
7
+ # #
8
+ #############################################################################
9
+
10
+ require 'rtype'
11
+
12
+ module Twisty
13
+
14
+ class Entity
15
+ attr_reader :id
16
+
17
+ rtype [Entity] => Boolean
18
+ def ==(other)
19
+ if other.class == self.class
20
+ return other.id == @id
21
+ elsif other.class == Symbol
22
+ return other == @id
23
+ else
24
+ return false
25
+ end
26
+ end
27
+
28
+ protected
29
+ def engine
30
+ return Engine.instance()
31
+ end
32
+ end
33
+
34
+ end
@@ -0,0 +1,25 @@
1
+ #############################################################################
2
+ # #
3
+ # Copyright (c) 2017, Ryan McCoskrie <work@ryanmccoskrie.me> #
4
+ # #
5
+ # This software is distributed under the MIT License which can be found #
6
+ # in the root directory. #
7
+ # #
8
+ #############################################################################
9
+
10
+ module Twisty
11
+
12
+ class TwistyError < RuntimeError
13
+ attr_reader :message
14
+
15
+ def initialize(s)
16
+ @message = s
17
+ end
18
+ end
19
+
20
+ class GameError < TwistyError
21
+ end
22
+ class PlayError < TwistyError
23
+ end
24
+
25
+ end
@@ -0,0 +1,99 @@
1
+ #############################################################################
2
+ # #
3
+ # Copyright (c) 2017, Ryan McCoskrie <work@ryanmccoskrie.me> #
4
+ # #
5
+ # This software is distributed under the MIT License which can be found #
6
+ # in the root directory. #
7
+ # #
8
+ #############################################################################
9
+
10
+ require_relative 'entity'
11
+
12
+ require 'rtype'
13
+
14
+
15
+ module Twisty
16
+
17
+ class Item < Entity
18
+ attr_reader :name, :desc, :fixed, :storage, :contents
19
+
20
+ def initialize(id, name, desc, fixed, storage)
21
+ @id = id
22
+ @name = name
23
+ @desc = desc
24
+ @fixed = fixed
25
+ @storage = storage
26
+ @contents = []
27
+ end
28
+
29
+ rtype [] => Boolean
30
+ def take_event
31
+ return true
32
+ end
33
+
34
+ rtype [] => Boolean
35
+ def drop_event
36
+ return true
37
+ end
38
+
39
+ rtype [] => nil
40
+ def look
41
+ puts @desc
42
+
43
+ if @storage > 0
44
+ puts "Contents:"
45
+
46
+ if @contents.length == 0
47
+ puts "Nothing"
48
+ else
49
+ @contents.each{|id| puts engine.items[id].name}
50
+ end
51
+ end
52
+
53
+ return nil
54
+ end
55
+
56
+ rtype [Symbol] => Boolean
57
+ def contains_item?(item)
58
+ return @contents.include?(item) if @storage > 0
59
+ return false
60
+ end
61
+
62
+ rtype [Symbol] => nil
63
+ def add_item(item)
64
+ if @storage == 0
65
+ raise GameError.new "#{@id} is not a container"
66
+ else
67
+ #Skip if already contained
68
+ if contains_item?(item) == false
69
+ @contents << item
70
+ end
71
+ end
72
+
73
+ return nil
74
+ end
75
+
76
+ rtype [Symbol] => nil
77
+ def del_item(item)
78
+ #Skip if already contained
79
+ if contains_item?(item)
80
+ @contents.delete item
81
+ end
82
+
83
+ return nil
84
+ end
85
+
86
+ rtype [Proc] => nil
87
+ def on_take(&block)
88
+ self.define_singleton_method(:take_event, &block)
89
+ return nil
90
+ end
91
+
92
+ rtype [Proc] => nil
93
+ def on_drop(&block)
94
+ self.define_singleton_method(:drop_event, &block)
95
+ return nil
96
+ end
97
+ end
98
+
99
+ end
@@ -0,0 +1,106 @@
1
+ #############################################################################
2
+ # #
3
+ # Copyright (c) 2017, Ryan McCoskrie <work@ryanmccoskrie.me> #
4
+ # #
5
+ # This software is distributed under the MIT License which can be found #
6
+ # in the root directory. #
7
+ # #
8
+ #############################################################################
9
+
10
+ require_relative 'entity.rb'
11
+
12
+ require 'rtype'
13
+
14
+ module Twisty
15
+
16
+ class Room < Entity
17
+ attr_reader :name, :desc, :doors
18
+ attr_accessor :items
19
+
20
+ rtype [Symbol, String, String] => Array
21
+ def initialize(id, name, desc)
22
+ @id = id
23
+ @name = name
24
+ @desc = desc
25
+ @doors = {}
26
+ @items = []
27
+ end
28
+
29
+ rtype [] => Boolean
30
+ def enter_event
31
+ return true
32
+ end
33
+
34
+ rtype [] => Boolean
35
+ def exit_event
36
+ return true
37
+ end
38
+
39
+ rtype [Symbol, String] => nil
40
+ def add_door(to, name)
41
+ if name.split().length != 1
42
+ raise GameError.new "Door name must be one word"
43
+ elsif @doors.has_key? name
44
+ raise GameError.new "Door with name #{name} already exist in #{@id}"
45
+ else
46
+ @doors[to] = name
47
+ end
48
+
49
+ return nil
50
+ end
51
+
52
+ rtype [Symbol] => Array.of(Symbol)
53
+ def add_item(id)
54
+ if @items.include? id
55
+ raise GameError.new "Duplicate item in room #{@id}"
56
+ else
57
+ @items << id
58
+ end
59
+ end
60
+
61
+ rtype [Proc] => nil
62
+ def on_enter(&block)
63
+ self.define_singleton_method(:enter_event, &block)
64
+ return nil
65
+ end
66
+
67
+ rtype [Proc] => nil
68
+ def on_exit(&block)
69
+ self.define_singleton_method(:exit_event, &block)
70
+ return nil
71
+ end
72
+
73
+ rtype [] => nil
74
+ def look
75
+ puts @desc
76
+
77
+ if @items.length == 0
78
+ puts "Nothing is located here"
79
+ elsif @items.length == 1
80
+ puts
81
+
82
+ puts "Located here is:"
83
+ puts engine.items[@items[0]].name
84
+ else
85
+ puts
86
+
87
+ puts "Located here are:"
88
+ @items.each{ |id| puts engine.items[id].name }
89
+ end
90
+
91
+ puts
92
+
93
+ if doors.length == 0
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
101
+
102
+ return nil
103
+ end
104
+ end
105
+
106
+ end
data/lib/twisty.rb ADDED
@@ -0,0 +1,106 @@
1
+ #############################################################################
2
+ # #
3
+ # Copyright (c) 2017, Ryan McCoskrie <work@ryanmccoskrie.me> #
4
+ # #
5
+ # This software is distributed under the MIT License which can be found #
6
+ # in the root directory. #
7
+ # #
8
+ #############################################################################
9
+
10
+ require_relative 'twisty/error.rb'
11
+ require_relative 'twisty/engine.rb'
12
+ require_relative 'twisty/command.rb'
13
+ require_relative 'twisty/entity.rb'
14
+ require_relative 'twisty/room.rb'
15
+ require_relative 'twisty/item.rb'
16
+
17
+
18
+ module Twisty
19
+
20
+ Engine.instance.define_command(
21
+ /^help$/,
22
+ "help",
23
+ "Write out the list of commands you are reading now") do |x|
24
+ @commands.values.each do |command|
25
+ puts "#{command.help1}:"
26
+ puts "#{command.help2}"
27
+ puts
28
+ end
29
+ end
30
+ Engine.instance.define_command(
31
+ /^look$/,
32
+ "look",
33
+ "Look at the current room") {|x| current_room.look()}
34
+
35
+ Engine.instance.define_command(
36
+ /^look at \w+$/,
37
+ "look at object",
38
+ "Look at a specific object") do |tokens|
39
+ found = false
40
+ current_items.each do |id|
41
+ if @items[id].name.downcase == tokens[2]
42
+ @items[id].look
43
+ found = true
44
+ break
45
+ end
46
+ end
47
+
48
+ #Error condidtion
49
+ raise PlayError.new "I see no #{tokens[2]}" unless found
50
+ end
51
+ Engine.instance.define_command(
52
+ /^inventory$/,
53
+ "inventory",
54
+ "Get a list of things you are carrying") do |x|
55
+ if @inventory.size == 0
56
+ puts "You are currently carrying nothing"
57
+ else
58
+ puts "You are currently carring: "
59
+ @inventory.each{|id| puts @items[id].name}
60
+ end
61
+ end
62
+ Engine.instance.define_command(
63
+ /^take \w+$/,
64
+ "take object",
65
+ "Take an object and carry it in your inventory") do |tokens|
66
+ take_item_by_name(tokens[1])
67
+ end
68
+ Engine.instance.define_command(
69
+ /^take \w+ from \w+$/,
70
+ "take object from container",
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])
73
+ end
74
+ Engine.instance.define_command(
75
+ /^drop \w+$/,
76
+ "drop object",
77
+ "Remove an object from your inventory and leave it in the room") do |tokens|
78
+ drop_item_by_name(tokens[1])
79
+ end
80
+ Engine.instance.define_command(
81
+ /^put \w+ in \w+$/,
82
+ "put item in container",
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])
85
+ end
86
+ Engine.instance.define_command(
87
+ /^walk \w+$/,
88
+ "walk exit",
89
+ "Walk out of the room through an exit") do |tokens|
90
+ found = false
91
+ current_doors.each_pair do |to, name|
92
+ if name.downcase == tokens[1]
93
+ goto to
94
+ found = true
95
+ break
96
+ end
97
+ end
98
+
99
+ #Error condition
100
+ raise PlayError.new "Where is #{tokens[1]}?" unless found
101
+ end
102
+ Engine.instance.define_command(
103
+ /^quit$/,
104
+ "quit",
105
+ "Stop playing the game") {|x| @playing = false}
106
+ end
metadata ADDED
@@ -0,0 +1,64 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: twisty
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2b
5
+ platform: ruby
6
+ authors:
7
+ - Ryan McCoskrie
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-02-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rtype-native
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.6.8
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.6.8
27
+ description: Adventure game library
28
+ email: work@ryanmccoskrie.me
29
+ executables: []
30
+ extensions: []
31
+ extra_rdoc_files: []
32
+ files:
33
+ - lib/twisty.rb
34
+ - lib/twisty/command.rb
35
+ - lib/twisty/engine.rb
36
+ - lib/twisty/entity.rb
37
+ - lib/twisty/error.rb
38
+ - lib/twisty/item.rb
39
+ - lib/twisty/room.rb
40
+ homepage: http://rubygems.org/gems/twisty
41
+ licenses:
42
+ - MIT
43
+ metadata: {}
44
+ post_install_message:
45
+ rdoc_options: []
46
+ require_paths:
47
+ - lib
48
+ required_ruby_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">"
56
+ - !ruby/object:Gem::Version
57
+ version: 1.3.1
58
+ requirements: []
59
+ rubyforge_project:
60
+ rubygems_version: 2.6.11
61
+ signing_key:
62
+ specification_version: 4
63
+ summary: Twisty
64
+ test_files: []