gamefic 1.5.1 → 1.6.0

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