gamefic 1.5.1 → 1.6.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 (70) hide show
  1. checksums.yaml +4 -4
  2. data/lib/gamefic.rb +1 -3
  3. data/lib/gamefic/action.rb +140 -79
  4. data/lib/gamefic/character.rb +120 -53
  5. data/lib/gamefic/character/state.rb +12 -0
  6. data/lib/gamefic/core_ext/array.rb +53 -11
  7. data/lib/gamefic/core_ext/string.rb +1 -0
  8. data/lib/gamefic/describable.rb +37 -11
  9. data/lib/gamefic/engine/base.rb +17 -4
  10. data/lib/gamefic/engine/tty.rb +4 -0
  11. data/lib/gamefic/entity.rb +4 -15
  12. data/lib/gamefic/matchable.rb +50 -0
  13. data/lib/gamefic/messaging.rb +45 -0
  14. data/lib/gamefic/node.rb +16 -0
  15. data/lib/gamefic/plot.rb +27 -33
  16. data/lib/gamefic/plot/{article_mount.rb → articles.rb} +22 -22
  17. data/lib/gamefic/plot/callbacks.rb +30 -4
  18. data/lib/gamefic/plot/{command_mount.rb → commands.rb} +121 -121
  19. data/lib/gamefic/plot/entities.rb +3 -3
  20. data/lib/gamefic/plot/host.rb +3 -3
  21. data/lib/gamefic/plot/playbook.rb +74 -30
  22. data/lib/gamefic/plot/scenes.rb +149 -0
  23. data/lib/gamefic/plot/snapshot.rb +14 -39
  24. data/lib/gamefic/plot/theater.rb +73 -0
  25. data/lib/gamefic/query.rb +6 -19
  26. data/lib/gamefic/query/base.rb +127 -246
  27. data/lib/gamefic/query/children.rb +6 -7
  28. data/lib/gamefic/query/descendants.rb +15 -0
  29. data/lib/gamefic/query/family.rb +19 -7
  30. data/lib/gamefic/query/itself.rb +13 -0
  31. data/lib/gamefic/query/matches.rb +67 -11
  32. data/lib/gamefic/query/parent.rb +6 -7
  33. data/lib/gamefic/query/siblings.rb +10 -7
  34. data/lib/gamefic/query/text.rb +39 -35
  35. data/lib/gamefic/scene.rb +1 -1
  36. data/lib/gamefic/scene/active.rb +12 -6
  37. data/lib/gamefic/scene/base.rb +56 -5
  38. data/lib/gamefic/scene/conclusion.rb +3 -0
  39. data/lib/gamefic/scene/custom.rb +0 -83
  40. data/lib/gamefic/scene/multiple_choice.rb +54 -32
  41. data/lib/gamefic/scene/multiple_scene.rb +11 -6
  42. data/lib/gamefic/scene/pause.rb +3 -4
  43. data/lib/gamefic/scene/yes_or_no.rb +23 -9
  44. data/lib/gamefic/script/base.rb +4 -0
  45. data/lib/gamefic/subplot.rb +22 -19
  46. data/lib/gamefic/syntax.rb +7 -15
  47. data/lib/gamefic/user/base.rb +7 -13
  48. data/lib/gamefic/user/buffer.rb +7 -0
  49. data/lib/gamefic/user/tty.rb +13 -12
  50. data/lib/gamefic/version.rb +1 -1
  51. metadata +11 -37
  52. data/lib/gamefic/director.rb +0 -23
  53. data/lib/gamefic/director/delegate.rb +0 -126
  54. data/lib/gamefic/director/order.rb +0 -17
  55. data/lib/gamefic/director/parser.rb +0 -137
  56. data/lib/gamefic/keywords.rb +0 -67
  57. data/lib/gamefic/plot/query_mount.rb +0 -9
  58. data/lib/gamefic/plot/scene_mount.rb +0 -182
  59. data/lib/gamefic/query/ambiguous_children.rb +0 -5
  60. data/lib/gamefic/query/expression.rb +0 -47
  61. data/lib/gamefic/query/many_children.rb +0 -7
  62. data/lib/gamefic/query/plural_children.rb +0 -14
  63. data/lib/gamefic/query/self.rb +0 -10
  64. data/lib/gamefic/scene_data.rb +0 -10
  65. data/lib/gamefic/scene_data/base.rb +0 -12
  66. data/lib/gamefic/scene_data/multiple_choice.rb +0 -19
  67. data/lib/gamefic/scene_data/multiple_scene.rb +0 -21
  68. data/lib/gamefic/scene_data/yes_or_no.rb +0 -18
  69. data/lib/gamefic/serialized.rb +0 -24
  70. data/lib/gamefic/stage.rb +0 -106
@@ -1,9 +0,0 @@
1
- module Gamefic
2
- module Plot::QueryMount
3
- end
4
- module Query
5
- def self.siblings *arguments
6
- Siblings.new *arguments
7
- end
8
- end
9
- end
@@ -1,182 +0,0 @@
1
- module Gamefic
2
-
3
- module Plot::SceneMount
4
- def default_scene
5
- @default_scene ||= Scene::Active.new(self)
6
- end
7
-
8
- def default_conclusion
9
- @default_conclusion ||= Scene::Conclusion.new
10
- end
11
-
12
- # Add a block to be executed when a player is added to the game.
13
- # Each Plot can only have one introduction. Subsequent calls will
14
- # overwrite the existing one.
15
- #
16
- # @example Welcome the player to the game
17
- # introduction do |actor|
18
- # actor.tell "Welcome to the game!"
19
- # end
20
- #
21
- # @yieldparam [Character]
22
- def introduction (&proc)
23
- @introduction = proc
24
- end
25
-
26
- # Introduce a player to the game.
27
- # This method is typically called by the Engine that manages game execution.
28
- def introduce(player)
29
- player.playbook = playbook
30
- player.cue default_scene
31
- p_players.push player
32
- @introduction.call(player) unless @introduction.nil?
33
- end
34
-
35
- # Create a multiple-choice scene.
36
- # The user will be required to make a valid choice to continue.
37
- #
38
- # @yieldparam [Character]
39
- # @yieldparam [Scene::Data::MultipleChoice]
40
- def multiple_choice *choices, &block
41
- s = Scene::MultipleChoice.new
42
- s.on_start do |actor, data|
43
- data.options.clear
44
- data.options.push *choices
45
- end
46
- s.on_finish &block
47
- s
48
- end
49
-
50
- # Create a yes-or-no scene.
51
- # The user will be required to answer Yes or No to continue.
52
- #
53
- # @yieldparam [Character]
54
- # @yieldparam [String] "yes" or "no"
55
- def yes_or_no prompt = nil, &block
56
- s = Scene::YesOrNo.new
57
- unless prompt.nil?
58
- s.on_start do |actor, data|
59
- data.prompt = prompt
60
- end
61
- end
62
- s.on_finish do |actor, data|
63
- block.call actor, data unless block.nil?
64
- actor.cue default_scene if actor.scene == s and actor.next_scene.nil?
65
- end
66
- s
67
- end
68
-
69
- def question prompt = 'What is your answer?', &block
70
- s = Scene::Custom.new
71
- s.on_start do |actor, data|
72
- data.prompt = prompt
73
- end
74
- s.on_finish &block
75
- s
76
- end
77
-
78
- # Create a scene that pauses the game.
79
- # This scene will execute the specified block and wait for input from the
80
- # the user (e.g., pressing Enter) to continue.
81
- #
82
- # @param key [Symbol] A unique name for the scene.
83
- # @param prompt [String] The text to display when prompting the user to continue.
84
- # @yieldparam [Character]
85
- # @yieldparam [Scene::Data::Base]
86
- def pause prompt = nil, &block
87
- s = Scene::Pause.new
88
- s.on_start do |actor, data|
89
- data.prompt = prompt unless prompt.nil?
90
- block.call actor, data unless block.nil?
91
- end
92
- s.on_finish do |actor, data|
93
- #actor.cue :active if actor.scene == key and actor.next_scene.nil?
94
- actor.cue default_scene if actor.scene == s and actor.next_scene.nil?
95
- end
96
- s
97
- end
98
-
99
- # Create a conclusion.
100
- # The game (or the character's participation in it) will end after this
101
- # scene is complete.
102
- #
103
- # @param key [Symbol] A unique name for the scene.
104
- # @yieldparam [Character]
105
- # @yieldparam [Scene::Data::Base]
106
- def conclusion &block
107
- s = Scene::Conclusion.new
108
- s.on_start &block
109
- s
110
- end
111
-
112
- # Create a custom scene.
113
- #
114
- # Custom scenes should always specify the next scene to be cued or
115
- # prepared. If not, the scene will get repeated on the next turn.
116
- #
117
- # This method creates a Scene::Custom by default. You can customize other
118
- # scene types by specifying the class to create.
119
- #
120
- # @example Ask the user for a name
121
- # scene :ask_for_name do |scene|
122
- # scene.on_start do |actor, data|
123
- # data.prompt = "What's your name?"
124
- # end
125
- # scene.on_finish do |actor, data|
126
- # actor.name = data.input
127
- # actor.tell "Hello, #{actor.name}!"
128
- # actor.cue :active
129
- # end
130
- # end
131
- #
132
- # @example Customize the prompt for a MultipleChoice scene
133
- # scene :ask_for_choice, Scene::MultipleChoice do |scene|
134
- # scene.on_start do |actor, data|
135
- # data.options.push 'red', 'green', 'blue'
136
- # data.prompt = "Which color?"
137
- # end
138
- # scene.on_finish do |actor, data|
139
- # actor.tell "You chose #{data.selection}"
140
- # actor.cue :active
141
- # end
142
- # end
143
- #
144
- # @param key [Symbol] A unique name for the scene.
145
- # @param key [cls] The class of scene to be instantiated.
146
- # @yieldparam [Scene::Custom] The instantiated scene.
147
- def scene cls = Scene::Custom, &block
148
- s = cls.new
149
- yield s if block_given?
150
- s
151
- end
152
-
153
- # Choose a new scene based on a list of options.
154
- # This is a specialized type of multiple-choice scene that determines
155
- # which scene to cue based on a Hash of choices and scene keys.
156
- #
157
- # @example Select a scene
158
- # multiple_scene :select_one_or_two, { "one" => :scene_one, "two" => :scene_two }
159
- # scene :scene_one do |actor|
160
- # actor.tell "You went to scene one"
161
- # end
162
- # scene :scene_two do |actor|
163
- # actor.tell "You went to scene two"
164
- # end
165
- # introduction do |actor|
166
- # actor.cue :select_one_or_two # The actor will be prompted to select "one" or "two" and get sent to the corresponding scene
167
- # end
168
- #
169
- # @param key [Symbol] A unique name for the scene.
170
- # @param map [Hash] A Hash of options and associated scene keys.
171
- def multiple_scene map
172
- s = Scene::MultipleScene.new
173
- s.on_start do |actor, data|
174
- map.each { |k, v|
175
- data.map k, v
176
- }
177
- end
178
- s
179
- end
180
- end
181
-
182
- end
@@ -1,5 +0,0 @@
1
- class Gamefic::Query::AmbiguousChildren < Gamefic::Query::ManyChildren
2
- def allow_ambiguous?
3
- true
4
- end
5
- end
@@ -1,47 +0,0 @@
1
- module Gamefic::Query
2
- class Expression < Base
3
- def base_specificity
4
- 10
5
- end
6
- def validate(subject, description)
7
- return false unless description.kind_of?(String)
8
- valid = false
9
- words = description.split_words
10
- words.each { |word|
11
- if description.include?(word)
12
- valid = true
13
- break
14
- end
15
- }
16
- valid
17
- end
18
- def execute(subject, description)
19
- if @arguments.length == 0
20
- return Matches.new([description], description, '')
21
- end
22
- keywords = Keywords.new(description)
23
- possible = []
24
- @arguments.each { |regexp|
25
- remainder = keywords.clone
26
- used = []
27
- while remainder.length > 0
28
- used.push remainder.shift
29
- if used.join(' ').match(regexp)
30
- possible.push Matches.new([used.join(' ')], used.join(' '), remainder.join(' '))
31
- end
32
- end
33
- }
34
- if possible.length > 0
35
- possible.sort! { |a, b|
36
- b.matching_text.length <=> a.matching_text.length
37
- }
38
- return possible[0]
39
- else
40
- return Matches.new([], '', description)
41
- end
42
- end
43
- def test_arguments arguments
44
- # No test for text
45
- end
46
- end
47
- end
@@ -1,7 +0,0 @@
1
- require 'gamefic/query/children'
2
-
3
- class Gamefic::Query::ManyChildren < Gamefic::Query::Children
4
- def allow_many?
5
- true
6
- end
7
- end
@@ -1,14 +0,0 @@
1
- class Gamefic::Query::PluralChildren < Gamefic::Query::AmbiguousChildren
2
- def execute(subject, description)
3
- if (!description.end_with?("s") and !description.end_with?("i") and !description.end_with?("ae")) or (description.end_with?("ous") or description.end_with?("ess"))
4
- return Gamefic::Query::Matches.new([], '', description)
5
- end
6
- super
7
- end
8
- def validate(subject, object)
9
- # Plural queries always return false on validation. Their only purpose is
10
- # to provide syntactic sugar for plural nouns, so it should never get triggered
11
- # by a token call.
12
- false
13
- end
14
- end
@@ -1,10 +0,0 @@
1
- module Gamefic::Query
2
- class Self < Base
3
- def base_specificity
4
- 30
5
- end
6
- def context_from(subject)
7
- [subject]
8
- end
9
- end
10
- end
@@ -1,10 +0,0 @@
1
- module Gamefic
2
-
3
- module SceneData
4
- autoload :Base, 'gamefic/scene_data/base'
5
- autoload :MultipleChoice, 'gamefic/scene_data/multiple_choice'
6
- autoload :MultipleScene, 'gamefic/scene_data/multiple_scene'
7
- autoload :YesOrNo, 'gamefic/scene_data/yes_or_no'
8
- end
9
-
10
- end
@@ -1,12 +0,0 @@
1
- module Gamefic
2
-
3
- class SceneData::Base
4
- attr_writer :prompt
5
- attr_accessor :input
6
-
7
- def prompt
8
- @prompt ||= '>'
9
- end
10
- end
11
-
12
- end
@@ -1,19 +0,0 @@
1
- module Gamefic
2
-
3
- class SceneData::MultipleChoice < SceneData::Base
4
- attr_accessor :selection
5
- attr_accessor :number
6
- attr_accessor :index
7
- attr_writer :invalid_message
8
- def options
9
- @options ||= []
10
- end
11
- def prompt
12
- @prompt ||= 'Enter a choice:'
13
- end
14
- def invalid_message
15
- @invalid_message ||= 'That is not a valid choice.'
16
- end
17
- end
18
-
19
- end
@@ -1,21 +0,0 @@
1
- module Gamefic
2
-
3
- class SceneData::MultipleScene < SceneData::MultipleChoice
4
- def options
5
- scene_map.keys
6
- end
7
-
8
- def map choice, scene
9
- scene_map[choice] = scene
10
- end
11
-
12
- def scene_for choice
13
- scene_map[choice]
14
- end
15
-
16
- def scene_map
17
- @scene_map ||= {}
18
- end
19
- end
20
-
21
- end
@@ -1,18 +0,0 @@
1
- module Gamefic
2
-
3
- class SceneData::YesOrNo < SceneData::Base
4
- def yes?
5
- input.to_s[0,1].downcase == 'y'
6
- end
7
- def no?
8
- input.to_s[0,1].downcase == 'n'
9
- end
10
- def prompt
11
- @prompt ||= 'Yes or No?'
12
- end
13
- def invalid_message
14
- @invalid_message ||= 'Please enter Yes or No.'
15
- end
16
- end
17
-
18
- end
@@ -1,24 +0,0 @@
1
- module Gamefic
2
- module Serialized
3
- def serialized_attributes
4
- self.class.serializer.keys
5
- end
6
- module ClassMethods
7
- def serialize *args
8
- args.each { |a|
9
- serializer[a] = nil
10
- }
11
- end
12
- def serializer
13
- @@serialized_attributes ||= from_superclass(:serializer, {}).dup
14
- end
15
- private
16
- def from_superclass(m, default = nil)
17
- superclass.respond_to?(m) ? superclass.send(m) : default
18
- end
19
- end
20
- def self.included(base)
21
- base.extend(Gamefic::Serialized::ClassMethods)
22
- end
23
- end
24
- end
data/lib/gamefic/stage.rb DELETED
@@ -1,106 +0,0 @@
1
- module Gamefic
2
-
3
- module Stage
4
- # Execute a block of code in a subset of the object's scope.
5
- #
6
- # An object's stage is an isolated namespace that has its own instance
7
- # variables and limited access to its parent's instance methods.
8
- def stage *args, &block
9
- s = generate_stage
10
- if block.nil?
11
- s.module_eval(*args)
12
- else
13
- s.module_exec(*args, &block)
14
- end
15
- end
16
-
17
- private
18
-
19
- def generate_stage
20
- return @stage unless @stage.nil?
21
-
22
- exposed = self.class.exposed_methods.keys
23
- mounted = self.class.mounted_modules.keys
24
- instance = self
25
-
26
- @stage = Module.new do
27
- define_singleton_method(:__instance__) do
28
- unless caller.length == 0 or caller[0].include?(__FILE__)
29
- raise NoMethodError.new("Method __instance__ is not available from the stage.")
30
- end
31
- instance
32
- end
33
- exposed.each do |exposed_method|
34
- define_singleton_method(exposed_method) do |*args, &block|
35
- __instance__.public_send(exposed_method, *args, &block)
36
- end
37
- end
38
- mounted.each { |dsl|
39
- dsl.public_instance_methods.each { |method|
40
- define_singleton_method(method) do |*args, &block|
41
- #puts "Calling a mounted method"
42
- result = __instance__.public_send(method, *args, &block)
43
- #puts "Done"
44
- result
45
- end
46
- }
47
- }
48
- end
49
-
50
- return @stage
51
- end
52
-
53
- module ClassMethods
54
- # Mount a module in this class.
55
- #
56
- # Mounting a module will include it like a typical mixin and expose its
57
- # public methods to the stage.
58
- #
59
- # Assuming you have a module Foo with one public method bar,
60
- # <code>mount Foo</code> is functionally equivalent to
61
- # <code>include Foo; expose bar</code>.
62
- def mount *args
63
- args.each { |a|
64
- include a
65
- mounted_modules[a] = nil
66
- }
67
- end
68
-
69
- # Give this object's stage access to an instance method.
70
- #
71
- # @example
72
- # class Container
73
- # def foobar; end
74
- # expose :foobar
75
- # end
76
- # x = Container.new
77
- # x.stage do
78
- # foobar
79
- # end
80
- def expose *args
81
- args.each { |a|
82
- exposed_methods[a] = nil
83
- }
84
- end
85
-
86
- def exposed_methods
87
- @@exposed_methods ||= from_superclass(:exposed_methods, {}).dup
88
- end
89
-
90
- def mounted_modules
91
- @@mounted_modules ||= from_superclass(:mounted_modules, {}).dup
92
- end
93
-
94
- private
95
-
96
- def from_superclass(m, default = nil)
97
- superclass.respond_to?(m) ? superclass.send(m) : default
98
- end
99
- end
100
-
101
- def self.included(base)
102
- base.extend(ClassMethods)
103
- end
104
- end
105
-
106
- end