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,120 +0,0 @@
1
- require 'gamefic/action'
2
-
3
- module Gamefic
4
-
5
- module Plot::Commands
6
- # Create an Action that responds to a command.
7
- # An Action uses the command argument to identify the imperative verb that
8
- # triggers the action.
9
- # It can also accept queries to tokenize the remainder of the input and
10
- # filter for particular entities or properties.
11
- # The block argument contains the code to be executed when the input
12
- # matches all of the Action's criteria (i.e., verb and queries).
13
- #
14
- # @example A simple Action.
15
- # respond :salute do |actor|
16
- # actor.tell "Hello, sir!"
17
- # end
18
- # # The command "salute" will respond "Hello, sir!"
19
- #
20
- # @example An Action that accepts a Character
21
- # respond :salute, Use.visible(Character) do |actor, character|
22
- # actor.tell "#{The character} returns your salute."
23
- # end
24
- #
25
- # @param command [Symbol] An imperative verb for the command
26
- # @param queries [Array<Query::Base>] Filters for the command's tokens
27
- # @yieldparam [Character]
28
- def respond(command, *queries, &proc)
29
- playbook.respond(command, *queries, &proc)
30
- end
31
-
32
- # Create a Meta Action that responds to a command.
33
- # Meta Actions are very similar to standard Actions, except the Plot
34
- # understands them to be commands that operate above and/or outside of the
35
- # actual game world. Examples of Meta Actions are commands that report the
36
- # player's current score, save and restore saved games, or list the game's
37
- # credits.
38
- #
39
- # @example A simple Meta Action
40
- # meta :credits do |actor|
41
- # actor.tell "This game was written by John Smith."
42
- # end
43
- #
44
- # @param command [Symbol] An imperative verb for the command
45
- # @param queries [Array<Query::Base>] Filters for the command's tokens
46
- # @yieldparam [Character]
47
- def meta(command, *queries, &proc)
48
- playbook.meta command, *queries, &proc
49
- end
50
-
51
- # @deprecated
52
- def action(command, *queries, &proc)
53
- respond command, *queries, &proc
54
- end
55
-
56
- # Declare a dismabiguation response for actions.
57
- # The disambigurator is executed when an action expects an argument to
58
- # reference a specific entity but its query matched more than one. For
59
- # example, "red" might refer to either a red key or a red book.
60
- #
61
- # If a disambiguator is not defined, the playbook will use its default
62
- # implementation.
63
- #
64
- # @example Tell the player the list of ambiguous entities.
65
- # disambiguate do |actor, entities|
66
- # actor.tell "I don't know which you mean: #{entities.join_or}."
67
- # end
68
- #
69
- # @yieldparam [Gamefic::Character]
70
- # @yieldparam [Array<Gamefic::Entity>]
71
- def disambiguate &block
72
- playbook.disambiguate &block
73
- end
74
-
75
- # Validate an order before a character can execute its command.
76
- #
77
- # @yieldparam [Gamefic::Director::Order]
78
- def validate &block
79
- playbook.validate &block
80
- end
81
-
82
- # Create an alternate Syntax for an Action.
83
- # The command and its translation can be parameterized.
84
- #
85
- # @example Create a synonym for the Inventory Action.
86
- # interpret "catalogue", "inventory"
87
- # # The command "catalogue" will be translated to "inventory"
88
- #
89
- # @example Create a parameterized synonym for the Look Action.
90
- # interpret "scrutinize :entity", "look :entity"
91
- # # The command "scrutinize chair" will be translated to "look chair"
92
- #
93
- # @param command [String] The format of the original command
94
- # @param translation [String] The format of the translated command
95
- # @return [Syntax] the Syntax object
96
- def interpret command, translation
97
- playbook.interpret command, translation
98
- end
99
-
100
- # @deprecated
101
- def xlate command, translation
102
- interpret command, translation
103
- end
104
-
105
- # Get an Array of available verbs.
106
- #
107
- # @return [Array<String>]
108
- def verbs
109
- playbook.verbs.map { |v| v.to_s }.reject{ |v| v.start_with?('_') }
110
- end
111
-
112
- # Get an Array of all Actions defined in the Plot.
113
- #
114
- # @return [Array<Action>]
115
- def actions
116
- playbook.actions
117
- end
118
- end
119
-
120
- end
@@ -1,15 +0,0 @@
1
- module Gamefic
2
-
3
- module Plot::Players
4
- def players
5
- p_players.clone
6
- end
7
-
8
- private
9
-
10
- def p_players
11
- @p_players ||= []
12
- end
13
- end
14
-
15
- end
@@ -1,187 +0,0 @@
1
- module Gamefic
2
-
3
- module Plot::Scenes
4
- def default_scene
5
- @default_scene ||= Scene::Activity
6
- end
7
-
8
- def default_conclusion
9
- @default_conclusion ||= Scene::Conclusion
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 [Gamefic::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
- #
29
- # @param [Gamefic::Character]
30
- def introduce(player)
31
- player.playbooks.push playbook unless player.playbooks.include?(playbook)
32
- player.cue default_scene
33
- p_players.push player
34
- @introduction.call(player) unless @introduction.nil?
35
- end
36
-
37
- # Create a multiple-choice scene.
38
- # The user will be required to make a valid choice to continue.
39
- #
40
- # @yieldparam [Gamefic::Character]
41
- # @yieldparam [Gamefic::Scene::Data::MultipleChoice]
42
- def multiple_choice *choices, &block
43
- s = Scene::MultipleChoice.subclass do |actor, scene|
44
- scene.options.concat choices
45
- scene.on_finish &block
46
- end
47
- scene_classes.push s
48
- s
49
- end
50
-
51
- # Create a yes-or-no scene.
52
- # The user will be required to answer Yes or No to continue.
53
- #
54
- # @yieldparam [Gamefic::Character]
55
- # @yieldparam [Gamefic::Scene::YesOrNo]
56
- def yes_or_no prompt = nil, &block
57
- s = Scene::YesOrNo.subclass do |actor, scene|
58
- scene.prompt = prompt
59
- scene.on_finish &block
60
- end
61
- scene_classes.push s
62
- s
63
- end
64
-
65
- # Create a scene with custom processing on user input.
66
- #
67
- # @example Echo the user's response
68
- # @scene = question 'What do you say?' do |actor, scene|
69
- # actor.tell "You said #{scene.input}"
70
- # end
71
- #
72
- # @yieldparam [Gamefic::Character]
73
- # @yieldparam [Gamefic::Scene::YesOrNo]
74
- def question prompt = 'What is your answer?', &block
75
- s = Scene::Custom.subclass do |actor, scene|
76
- scene.prompt = prompt
77
- scene.on_finish &block
78
- end
79
- scene_classes.push s
80
- s
81
- end
82
-
83
- # Create a scene that pauses the game.
84
- # This scene will execute the specified block and wait for input from the
85
- # the user (e.g., pressing Enter) to continue.
86
- #
87
- # @param prompt [String] The text to display when prompting the user to continue.
88
- # @yieldparam [Gamefic::Character]
89
- # @yieldparam [Gamefic::Scene::Pause]
90
- def pause prompt = nil, &block
91
- s = Scene::Pause.subclass do |actor, scene|
92
- scene.prompt = prompt unless prompt.nil?
93
- block.call(actor, scene) unless block.nil?
94
- end
95
- scene_classes.push s
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
- # @yieldparam [Gamefic::Character]
104
- # @yieldparam [Gamefic::Scene::Conclusion]
105
- def conclusion &block
106
- s = Scene::Conclusion.subclass &block
107
- scene_classes.push s
108
- s
109
- end
110
-
111
- # Create a custom scene.
112
- #
113
- # Custom scenes should always specify the next scene to be cued or
114
- # prepared. If not, the scene will get repeated on the next turn.
115
- #
116
- # This method creates a Scene::Custom by default. You can customize other
117
- # scene types by specifying the class to create.
118
- #
119
- # @example Ask the user for a name
120
- # @scene = custom do |scene|
121
- # data.prompt = "What's your name?"
122
- # scene.on_finish do |actor, data|
123
- # actor.name = data.input
124
- # actor.tell "Hello, #{actor.name}!"
125
- # actor.cue :active
126
- # end
127
- # end
128
- #
129
- # @param cls [Class] The class of scene to be instantiated.
130
- # @yieldparam [Gamefic::Character]
131
- # @yieldparam [Scene::Custom] The instantiated scene.
132
- def custom cls = Scene::Custom, &block
133
- s = cls.subclass &block
134
- scene_classes.push s
135
- s
136
- end
137
-
138
- # Choose a new scene based on a list of options.
139
- # This is a specialized type of multiple-choice scene that determines
140
- # which scene to cue based on a Hash of choices and scene keys.
141
- #
142
- # @example Select a scene
143
- # scene_one = pause do |actor|
144
- # actor.tell "You went to scene one"
145
- # end
146
- #
147
- # scene_two = pause do |actor|
148
- # actor.tell "You went to scene two"
149
- # end
150
- #
151
- # select_one_or_two = multiple_scene "One" => scene_one, "Two" => scene_two
152
- #
153
- # introduction do |actor|
154
- # actor.cue select_one_or_two # The actor will be prompted to select "one" or "two" and get sent to the corresponding scene
155
- # end
156
- #
157
- # @example Customize options
158
- # scene_one = pause # do...
159
- # scene_two = pause # do...
160
- #
161
- # # Some event in the game sets actor[:can_go_to_scene_two] to true
162
- #
163
- # select_one_or_two = multiple_scene do |actor, scene|
164
- # scene.map "Go to scene one", scene_one
165
- # scene.map "Go to scene two", scene_two if actor[:can_go_to_scene_two]
166
- # end
167
- #
168
- # @param map [Hash] A Hash of options and associated scenes.
169
- # @yieldparam [Gamefic::Character]
170
- # @yieldparam [Gamefic::Scene::MultipleScene]
171
- def multiple_scene map = {}, &block
172
- s = Scene::MultipleScene.subclass do |actor, scene|
173
- map.each_pair { |k, v|
174
- scene.map k, v
175
- }
176
- block.call actor, scene unless block.nil?
177
- end
178
- scene_classes.push s
179
- s
180
- end
181
-
182
- def scene_classes
183
- @scene_classes ||= []
184
- end
185
- end
186
-
187
- end
@@ -1,73 +0,0 @@
1
- module Gamefic
2
-
3
- module Plot::Theater
4
- # Execute a block of code in a subset of the object's scope. An object's
5
- # stage is an isolated namespace that has its own instance variables and
6
- # access to its owner's public methods.
7
- #
8
- # There are two ways to execute code on the stage. It will accept either a
9
- # string of code with an optional file name and line number, or a proc
10
- # with optional arguments. See module_eval and module_exec for more
11
- # information.
12
- #
13
- # @example Evaluate a string of code
14
- # stage "puts 'Hello'"
15
- #
16
- # @example Evaluate a string of code with a file name and line number
17
- # stage "puts 'Hello'", "file.rb", 1
18
- #
19
- # @example Execute a block of code
20
- # stage {
21
- # puts 'Hello'
22
- # }
23
- #
24
- # @example Execute a block of code with arguments
25
- # stage 'hello' { |message|
26
- # puts message # <- prints 'hello'
27
- # }
28
- #
29
- # @example Use an instance variable
30
- # stage "@message = 'hello'"
31
- # stage "puts @message" # <- prints 'hello'
32
- #
33
- # @return [Object] The value returned by the executed code
34
- def stage *args, &block
35
- if block.nil?
36
- theater.module_eval *args
37
- else
38
- theater.module_exec *args, &block
39
- end
40
- end
41
-
42
- # The module that acts as an isolated namespace for staged code.
43
- #
44
- # @return [Module]
45
- def theater
46
- return @theater unless @theater.nil?
47
- instance = self
48
-
49
- @theater = Module.new do
50
- define_singleton_method :method_missing do |symbol, *args, &block|
51
- instance.public_send :public_send, symbol, *args, &block
52
- end
53
-
54
- define_singleton_method :stage do |*args|
55
- raise NoMethodError.new("The stage method is not available from inside staged scripts")
56
- end
57
-
58
- define_singleton_method :to_s do
59
- "[Theater]"
60
- end
61
- end
62
-
63
- # HACK: Include the theater module in Object so that classes and modules
64
- # defined in scripts are accessible from procs passed to the stage.
65
- Object.class_exec(@theater) do |t|
66
- include t
67
- end
68
-
69
- @theater
70
- end
71
- end
72
-
73
- end
@@ -1,22 +0,0 @@
1
- require 'gamefic'
2
- require 'gamefic/grammar'
3
-
4
- module Gamefic
5
- module Plot::YouMount
6
- class YouGrammarSet
7
- include Grammar::Gender
8
- include Grammar::Person
9
- include Grammar::Plural
10
- include Grammar::WordAdapter
11
- end
12
- # @return [YouGrammarSet]
13
- def you
14
- if @you.nil?
15
- @you = YouGrammarSet.new
16
- @you.person = 2
17
- end
18
- @you
19
- end
20
- end
21
-
22
- end
@@ -1,13 +0,0 @@
1
- module Gamefic
2
-
3
- # Script classes provide code to be executed in Plots. They are accessed
4
- # through Source classes, e.g., a Source::Text object is used to find
5
- # Source::Files.
6
- #
7
- module Script
8
- autoload :Base, 'gamefic/script/base'
9
- autoload :File, 'gamefic/script/file'
10
- autoload :Text, 'gamefic/script/text'
11
- end
12
-
13
- end
@@ -1,42 +0,0 @@
1
- module Gamefic
2
-
3
- class Script::Base
4
- def initialize
5
- raise "#initialize must be defined in subclasses"
6
- end
7
-
8
- # Get the script's text.
9
- # The text must be source code suitable for evaluation via Plot#stage.
10
- #
11
- # @return [String]
12
- def read
13
- raise "#read must be defined in subclasses"
14
- end
15
-
16
- # Get the script's path.
17
- #
18
- # @return [String]
19
- def path
20
- raise "#path must be defined in subclasses"
21
- end
22
-
23
- # Get the absolute path of the script's original file, or its URL for
24
- # sources that are not file-based.
25
- #
26
- # @return [String]
27
- def absolute_path
28
- raise "#absolute_path must be defined in subclasses"
29
- end
30
-
31
- # Script objects are equal if their relative paths are the same. Note that
32
- # they are still considered equal if their absolute paths are different,
33
- # or even if they come from different types of sources.
34
- #
35
- # @param other[Script::Base]
36
- # @return [Boolean]
37
- def==(other)
38
- path == other.path
39
- end
40
- end
41
-
42
- end