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,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