gamefic 1.7.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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