gamefic 1.7.0 → 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.
Files changed (99) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +12 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +13 -0
  5. data/.solargraph.yml +5 -0
  6. data/Gemfile +7 -0
  7. data/LICENSE +20 -0
  8. data/README.md +28 -0
  9. data/Rakefile +10 -0
  10. data/gamefic.gemspec +27 -0
  11. data/lib/gamefic.rb +7 -6
  12. data/lib/gamefic/action.rb +38 -28
  13. data/lib/gamefic/active.rb +325 -280
  14. data/lib/gamefic/actor.rb +8 -5
  15. data/lib/gamefic/command.rb +9 -7
  16. data/lib/gamefic/core_ext/array.rb +24 -49
  17. data/lib/gamefic/core_ext/string.rb +25 -16
  18. data/lib/gamefic/describable.rb +21 -23
  19. data/lib/gamefic/element.rb +43 -31
  20. data/lib/gamefic/entity.rb +6 -12
  21. data/lib/gamefic/index.rb +121 -0
  22. data/lib/gamefic/{matchable.rb → keywords.rb} +52 -50
  23. data/lib/gamefic/messaging.rb +43 -44
  24. data/lib/gamefic/node.rb +14 -5
  25. data/lib/gamefic/plot.rb +69 -89
  26. data/lib/gamefic/plot/darkroom.rb +92 -264
  27. data/lib/gamefic/plot/host.rb +42 -48
  28. data/lib/gamefic/plot/snapshot.rb +5 -18
  29. data/lib/gamefic/query.rb +14 -18
  30. data/lib/gamefic/query/base.rb +30 -18
  31. data/lib/gamefic/query/children.rb +0 -0
  32. data/lib/gamefic/query/external.rb +18 -14
  33. data/lib/gamefic/query/family.rb +1 -7
  34. data/lib/gamefic/query/matches.rb +75 -67
  35. data/lib/gamefic/query/parent.rb +0 -0
  36. data/lib/gamefic/query/siblings.rb +0 -0
  37. data/lib/gamefic/query/text.rb +2 -1
  38. data/lib/gamefic/scene.rb +0 -2
  39. data/lib/gamefic/scene/activity.rb +24 -26
  40. data/lib/gamefic/scene/base.rb +64 -8
  41. data/lib/gamefic/scene/conclusion.rb +0 -2
  42. data/lib/gamefic/scene/custom.rb +0 -2
  43. data/lib/gamefic/scene/multiple_choice.rb +18 -3
  44. data/lib/gamefic/scene/multiple_scene.rb +29 -20
  45. data/lib/gamefic/scene/pause.rb +7 -2
  46. data/lib/gamefic/scene/yes_or_no.rb +21 -9
  47. data/lib/gamefic/scriptable.rb +87 -0
  48. data/lib/gamefic/serialize.rb +68 -0
  49. data/lib/gamefic/subplot.rb +29 -35
  50. data/lib/gamefic/syntax.rb +14 -13
  51. data/lib/gamefic/version.rb +3 -3
  52. data/lib/gamefic/world.rb +16 -0
  53. data/lib/gamefic/world/callbacks.rb +135 -0
  54. data/lib/gamefic/world/commands.rb +184 -0
  55. data/lib/gamefic/{plot → world}/entities.rb +30 -29
  56. data/lib/gamefic/{plot → world}/playbook.rb +255 -240
  57. data/lib/gamefic/world/players.rb +21 -0
  58. data/lib/gamefic/world/scenes.rb +226 -0
  59. metadata +41 -92
  60. data/bin/gamefic +0 -9
  61. data/lib/gamefic/engine.rb +0 -7
  62. data/lib/gamefic/engine/base.rb +0 -59
  63. data/lib/gamefic/engine/tty.rb +0 -24
  64. data/lib/gamefic/grammar.rb +0 -13
  65. data/lib/gamefic/grammar/conjugator.rb +0 -20
  66. data/lib/gamefic/grammar/gender.rb +0 -11
  67. data/lib/gamefic/grammar/person.rb +0 -10
  68. data/lib/gamefic/grammar/plural.rb +0 -13
  69. data/lib/gamefic/grammar/pronouns.rb +0 -106
  70. data/lib/gamefic/grammar/tense.rb +0 -6
  71. data/lib/gamefic/grammar/verb_set.rb +0 -43
  72. data/lib/gamefic/grammar/verbs.rb +0 -26
  73. data/lib/gamefic/grammar/word_adapter.rb +0 -49
  74. data/lib/gamefic/plot/articles.rb +0 -22
  75. data/lib/gamefic/plot/callbacks.rb +0 -126
  76. data/lib/gamefic/plot/commands.rb +0 -120
  77. data/lib/gamefic/plot/players.rb +0 -15
  78. data/lib/gamefic/plot/scenes.rb +0 -187
  79. data/lib/gamefic/plot/theater.rb +0 -73
  80. data/lib/gamefic/plot/you_mount.rb +0 -22
  81. data/lib/gamefic/script.rb +0 -13
  82. data/lib/gamefic/script/base.rb +0 -42
  83. data/lib/gamefic/script/file.rb +0 -14
  84. data/lib/gamefic/script/text.rb +0 -14
  85. data/lib/gamefic/shell.rb +0 -76
  86. data/lib/gamefic/source.rb +0 -14
  87. data/lib/gamefic/source/base.rb +0 -12
  88. data/lib/gamefic/source/file.rb +0 -23
  89. data/lib/gamefic/source/text.rb +0 -16
  90. data/lib/gamefic/tester.rb +0 -19
  91. data/lib/gamefic/text.rb +0 -8
  92. data/lib/gamefic/text/ansi.rb +0 -53
  93. data/lib/gamefic/text/html.rb +0 -68
  94. data/lib/gamefic/text/html/conversions.rb +0 -250
  95. data/lib/gamefic/text/html/entities.rb +0 -9
  96. data/lib/gamefic/tty.rb +0 -10
  97. data/lib/gamefic/user.rb +0 -7
  98. data/lib/gamefic/user/base.rb +0 -29
  99. data/lib/gamefic/user/tty.rb +0 -38
@@ -1,5 +1,8 @@
1
- module Gamefic
2
- class Actor < Gamefic::Entity
3
- include Gamefic::Active
4
- end
5
- end
1
+ module Gamefic
2
+ # An entity that is capable of performing actions and participating in
3
+ # scenes.
4
+ #
5
+ class Actor < Gamefic::Entity
6
+ include Gamefic::Active
7
+ end
8
+ end
@@ -1,16 +1,18 @@
1
1
  module Gamefic
2
2
  # A Command is a collection of tokens parsed from a Syntax.
3
- # The Director uses Commands to find and execute corresponding Actions.
3
+ # Playbooks use Commands to find and execute corresponding Actions.
4
4
  #
5
5
  class Command
6
- # @!attribute [r] verb
7
- # @return [Symbol] A Symbol representing the command's verb or verbal phrase.
6
+ # A Symbol representing the command's verb or verbal phrase.
7
+ #
8
+ # @return [Symbol]
8
9
  attr_reader :verb
9
-
10
- # @!attribute [r] arguments
11
- # @return [Array<String>] An Array of arguments to be mapped to an Action's Queries.
10
+
11
+ # An Array of arguments to be mapped to an Action's Queries.
12
+ #
13
+ # @return [Array<String>]
12
14
  attr_reader :arguments
13
-
15
+
14
16
  def initialize verb, arguments
15
17
  @verb = verb
16
18
  @arguments = arguments
@@ -1,5 +1,5 @@
1
1
  class Array
2
- # Get a subset of the array that matches the argument.
2
+ # Get a subset of the array that matches the arguments.
3
3
  # If the argument is a Class or Module, the elements must be of the type.
4
4
  # If the argument is a Symbol, it should be a method for which the elements must return true.
5
5
  # If the argument is an Object, the elements must equal the object.
@@ -11,45 +11,24 @@ class Array
11
11
  # animals.that_are(:nil?) #=> [nil]
12
12
  #
13
13
  # @return [Array]
14
- def that_are(cls)
15
- if (cls.kind_of?(Class) or cls.kind_of?(Module))
16
- return self.clone.delete_if { |i| i.kind_of?(cls) == false }
17
- elsif cls.kind_of?(Symbol)
18
- return self.clone.delete_if { |i| i.send(cls) == false }
19
- else
20
- if self.include?(cls)
21
- return [cls]
22
- end
23
- return Array.new
14
+ def that_are(*cls)
15
+ result = self.clone
16
+ cls.each do |c|
17
+ _keep result, c, true
24
18
  end
19
+ result
25
20
  end
26
21
 
27
- # Get a subset of the array that does not match the argument.
22
+ # Get a subset of the array that does not match the arguments.
28
23
  # See Array#that_are for information about how arguments are evaluated.
29
24
  #
30
25
  # @return [Array]
31
- def that_are_not(cls)
32
- if (cls.kind_of?(Class) or cls.kind_of?(Module))
33
- return self.clone.delete_if { |i| i.kind_of?(cls) == true }
34
- elsif cls.kind_of?(Symbol)
35
- return self.clone.delete_if { |i| i.send(cls) == true }
36
- else
37
- return self.clone - [cls]
26
+ def that_are_not(*cls)
27
+ result = self.clone
28
+ cls.each do |c|
29
+ _keep result, c, false
38
30
  end
39
- end
40
-
41
- # Get a random element from the array.
42
- # @deprecated Use Array#sample instead.
43
- #
44
- def random
45
- return self[rand(self.length)]
46
- end
47
-
48
- # Pop a random element from the array.
49
- # @deprecated Use Array#pop_sample instead.
50
- #
51
- def pop_random
52
- pop_sample
31
+ result
53
32
  end
54
33
 
55
34
  # Pop a random element from the array.
@@ -58,22 +37,6 @@ class Array
58
37
  delete_at(rand(self.length))
59
38
  end
60
39
 
61
- # @todo Candidate for deprecation
62
- # @return [Array]
63
- #def shuffle
64
- # self.sort { |a, b|
65
- # rand(3) <=> rand(3)
66
- # }
67
- #end
68
-
69
- # @todo Candidate for deprecation
70
- # @return [Array]
71
- #def shuffle!
72
- # self.sort! { |a, b|
73
- # rand(3) <=> rand(3)
74
- # }
75
- #end
76
-
77
40
  # Get a string representation of the array that separates elements with
78
41
  # commas and adds a conjunction before the last element.
79
42
  #
@@ -97,4 +60,16 @@ class Array
97
60
  def join_or(sep = ', ', orSep = ' or ', serial = true)
98
61
  join_and(sep, orSep, serial)
99
62
  end
63
+
64
+ # private
65
+
66
+ def _keep(arr, cls, bool)
67
+ if (cls.kind_of?(Class) or cls.kind_of?(Module))
68
+ arr.keep_if { |i| i.is_a?(cls) == bool }
69
+ elsif cls.kind_of?(Symbol)
70
+ arr.keep_if { |i| i.send(cls) == bool }
71
+ else
72
+ arr.keep_if {|i| (i == cls) == bool}
73
+ end
74
+ end
100
75
  end
@@ -1,16 +1,25 @@
1
- class String
2
- include Gamefic::Matchable
3
- # Capitalize the first letter without changing the rest of the string.
4
- # (String#capitalize makes the rest of the string lower-case.)
5
- def capitalize_first
6
- "#{self[0,1].upcase}#{self[1,self.length]}"
7
- end
8
- # @return [String]
9
- def cap_first
10
- self.capitalize_first
11
- end
12
- # @return [Array]
13
- def split_words
14
- self.gsub(/ +/, ' ').strip.split
15
- end
16
- end
1
+ class String
2
+ include Gamefic::Keywords
3
+
4
+ # Capitalize the first letter without changing the rest of the string.
5
+ # (String#capitalize makes the rest of the string lower-case.)
6
+ #
7
+ # @return [String] The capitalized text
8
+ def capitalize_first
9
+ "#{self[0,1].upcase}#{self[1,self.length]}"
10
+ end
11
+
12
+ # An alias for #capitalize_first.
13
+ #
14
+ # @return [String]
15
+ def cap_first
16
+ self.capitalize_first
17
+ end
18
+
19
+ # Get an array of words split by any whitespace.
20
+ #
21
+ # @return [Array]
22
+ def split_words
23
+ self.gsub(/[\s]+/, ' ').strip.split
24
+ end
25
+ end
@@ -1,13 +1,8 @@
1
- #require 'gamefic/keywords'
2
- require 'gamefic/grammar'
3
-
4
1
  module Gamefic
5
-
6
2
  # Add a variety of text properties for naming, describing, and referencing
7
3
  # objects.
8
4
  module Describable
9
- include Grammar::Person, Grammar::Plural
10
- include Matchable
5
+ include Keywords
11
6
 
12
7
  # Get the name of the object.
13
8
  # The name is usually presented without articles (e.g., "object" instead
@@ -17,25 +12,28 @@ module Gamefic
17
12
  # @return [String]
18
13
  attr_reader :name
19
14
 
15
+ # Alternate words that can be used to describe the object. Synonyms are
16
+ # used in conjunction with the object's name when generating keywords.
17
+ #
20
18
  # @return [String]
21
19
  attr_reader :synonyms
22
20
 
23
- # Get the object's indefinite article (usually "a" or "an").
21
+ # The object's indefinite article (usually "a" or "an").
24
22
  #
25
23
  # @return [String]
26
24
  attr_reader :indefinite_article
27
25
 
28
- # Get the object's definite article (usually "the").
26
+ # The object's definite article (usually "the").
29
27
  #
30
28
  # @return [String]
31
29
  attr_reader :definite_article
32
30
 
33
- # Get a set of Keywords associated with the object.
31
+ # Get a set of keywords associated with the object.
34
32
  # Keywords are typically the words in the object's name plus its synonyms.
35
33
  #
36
- # @return [Keywords]
34
+ # @return [Array<String>]
37
35
  def keywords
38
- @keywords ||= "#{definite_article} #{indefinite_article} #{name} #{synonyms}".downcase.split(Matchable::SPLIT_REGEXP).uniq
36
+ @keywords ||= "#{definite_article} #{indefinite_article} #{name} #{synonyms}".downcase.split(Keywords::SPLIT_REGEXP).uniq
39
37
  end
40
38
 
41
39
  # Get the name of the object with an indefinite article.
@@ -46,7 +44,7 @@ module Gamefic
46
44
  def indefinitely
47
45
  ((proper_named? or indefinite_article == '') ? '' : "#{indefinite_article} ") + name.to_s
48
46
  end
49
-
47
+
50
48
  # Get the name of the object with a definite article.
51
49
  # Note: proper-named objects never append an article, though an article
52
50
  # may be included in its proper name.
@@ -55,14 +53,14 @@ module Gamefic
55
53
  def definitely
56
54
  ((proper_named? or definite_article == '') ? '' : "#{definite_article} ") + name.to_s
57
55
  end
58
-
56
+
59
57
  # Get the definite article for this object (usually "the").
60
58
  #
61
59
  # @return [String]
62
60
  def definite_article
63
61
  @definite_article || "the"
64
62
  end
65
-
63
+
66
64
  # Set the definite article.
67
65
  #
68
66
  # @param [String] article
@@ -78,7 +76,7 @@ module Gamefic
78
76
  @keywords = nil
79
77
  @indefinite_article = article
80
78
  end
81
-
79
+
82
80
  # Is the object proper-named?
83
81
  # Proper-named objects typically do not add articles to their names when
84
82
  # referenced #definitely or #indefinitely, e.g., "Jane Doe" instead of
@@ -88,7 +86,7 @@ module Gamefic
88
86
  def proper_named?
89
87
  (@proper_named == true)
90
88
  end
91
-
89
+
92
90
  # Set whether the object has a proper name.
93
91
  #
94
92
  # @param bool [Boolean]
@@ -101,7 +99,7 @@ module Gamefic
101
99
  end
102
100
  @proper_named = bool
103
101
  end
104
-
102
+
105
103
  # Set the name of the object.
106
104
  # Setting the name performs some magic to determine how to handle
107
105
  # articles ("an object" and "the object").
@@ -132,21 +130,21 @@ module Gamefic
132
130
  end
133
131
  @name = value
134
132
  end
135
-
133
+
136
134
  # Does the object have a description?
137
135
  #
138
136
  # @return [Boolean]
139
137
  def has_description?
140
138
  (@description.to_s != '')
141
139
  end
142
-
140
+
143
141
  # Get the object's description.
144
142
  #
145
143
  # @return [String]
146
144
  def description
147
145
  @description || (Describable.default_description % { :name => self.definitely, :Name => self.definitely.capitalize_first })
148
146
  end
149
-
147
+
150
148
  # Set the object's description.
151
149
  #
152
150
  # @param text [String]
@@ -157,7 +155,7 @@ module Gamefic
157
155
  @description = nil
158
156
  end
159
157
  end
160
-
158
+
161
159
  def synonyms= text
162
160
  @keywords = nil
163
161
  @synonyms = text
@@ -172,14 +170,14 @@ module Gamefic
172
170
  def self.default_description=(text)
173
171
  @default_description = text
174
172
  end
175
-
173
+
176
174
  # Get the object's default description.
177
175
  #
178
176
  # @return [String]
179
177
  def self.default_description
180
178
  @default_description || "There's nothing special about %{name}."
181
179
  end
182
-
180
+
183
181
  # Get a String representation of the object. By default, this is the
184
182
  # object's name with an indefinite article, e.g., "a person" or "a red
185
183
  # dog."
@@ -1,31 +1,43 @@
1
- module Gamefic
2
- class Element
3
- include Gamefic::Describable
4
-
5
- def initialize(args = {})
6
- self.class.default_attributes.merge(args).each { |key, value|
7
- send "#{key}=", value
8
- }
9
- post_initialize
10
- yield self if block_given?
11
- end
12
-
13
- def post_initialize
14
- # raise NotImplementedError, "#{self.class} must implement post_initialize"
15
- end
16
-
17
- class << self
18
- def set_default attrs = {}
19
- default_attributes.merge! attrs
20
- end
21
-
22
- def default_attributes
23
- @default_attributes ||= {}
24
- end
25
-
26
- def inherited subclass
27
- subclass.set_default default_attributes
28
- end
29
- end
30
- end
31
- end
1
+ module Gamefic
2
+ # The simplest class that can compose an object for use in a plot.
3
+ # Most game objects, especially tangible items in the game, should derive
4
+ # from the Entity class. Elements, on the other hand, can be used for
5
+ # abstractions and ideas that don't have a physical presence but still might
6
+ # need to be referenced in a command.
7
+ #
8
+ class Element
9
+ include Gamefic::Describable
10
+ include Gamefic::Index
11
+
12
+ # @todo It would be nice if this initialization wasn't necessary.
13
+ def initialize(args = {})
14
+ super self.class.default_attributes.merge(args)
15
+ post_initialize
16
+ yield self if block_given?
17
+ end
18
+
19
+ def post_initialize
20
+ # raise NotImplementedError, "#{self.class} must implement post_initialize"
21
+ end
22
+
23
+ class << self
24
+ # Set or update the default values for new instances.
25
+ #
26
+ # @param attrs [Hash] The attributes to be merged into the defaults.
27
+ def set_default attrs = {}
28
+ default_attributes.merge! attrs
29
+ end
30
+
31
+ # A hash of default values for attributes when creating an instance.
32
+ #
33
+ # @return [Hash]
34
+ def default_attributes
35
+ @default_attributes ||= {}
36
+ end
37
+
38
+ def inherited subclass
39
+ subclass.set_default default_attributes
40
+ end
41
+ end
42
+ end
43
+ end
@@ -3,22 +3,17 @@ require "gamefic/describable"
3
3
  require 'gamefic/messaging'
4
4
 
5
5
  module Gamefic
6
-
6
+ # A physical object that can exist in a plot. Most objects with which
7
+ # players interact are entities. Player characters themselves typically
8
+ # derive from entities, e.g., the Gamefic::Actor class.
9
+ #
7
10
  class Entity < Element
8
11
  include Node
9
12
  include Messaging
10
- include Grammar::WordAdapter
11
13
 
12
- # Execute the entity's on_update blocks.
13
- # This method is typically called by the Engine that manages game execution.
14
- # The base method does nothing. Subclasses can override it.
15
- #
16
- def update
17
- end
18
-
19
14
  # Set the Entity's parent.
20
15
  #
21
- # @param node [Entity] The new parent.
16
+ # @param node [Gamefic::Entity] The new parent.
22
17
  def parent=(node)
23
18
  if node != nil and node.kind_of?(Entity) == false
24
19
  raise "Entity's parent must be an Entity"
@@ -43,7 +38,7 @@ module Gamefic
43
38
  def [](key)
44
39
  session[key]
45
40
  end
46
-
41
+
47
42
  # Set a custom property.
48
43
  #
49
44
  # @param key [Symbol] The property's name
@@ -52,5 +47,4 @@ module Gamefic
52
47
  session[key] = value
53
48
  end
54
49
  end
55
-
56
50
  end