gamefic 2.4.0 → 3.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 (102) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rspec.yml +41 -40
  3. data/.rspec-opal +2 -0
  4. data/.solargraph.yml +20 -3
  5. data/CHANGELOG.md +9 -0
  6. data/Rakefile +11 -1
  7. data/bin/console +14 -0
  8. data/bin/setup +8 -0
  9. data/gamefic.gemspec +5 -2
  10. data/lib/gamefic/action.rb +52 -183
  11. data/lib/gamefic/active/cue.rb +25 -0
  12. data/lib/gamefic/active/epic.rb +68 -0
  13. data/lib/gamefic/active/messaging.rb +43 -0
  14. data/lib/gamefic/active/take.rb +69 -0
  15. data/lib/gamefic/active.rb +95 -192
  16. data/lib/gamefic/actor.rb +2 -0
  17. data/lib/gamefic/block.rb +28 -0
  18. data/lib/gamefic/command.rb +16 -6
  19. data/lib/gamefic/core_ext/array.rb +4 -4
  20. data/lib/gamefic/core_ext/string.rb +10 -5
  21. data/lib/gamefic/describable.rb +39 -65
  22. data/lib/gamefic/dispatcher.rb +63 -32
  23. data/lib/gamefic/entity.rb +44 -19
  24. data/lib/gamefic/logging.rb +32 -0
  25. data/lib/gamefic/messenger.rb +66 -0
  26. data/lib/gamefic/narrative.rb +104 -0
  27. data/lib/gamefic/node.rb +44 -53
  28. data/lib/gamefic/plot.rb +60 -93
  29. data/lib/gamefic/props/default.rb +41 -0
  30. data/lib/gamefic/props/multiple_choice.rb +65 -0
  31. data/lib/gamefic/props/pause.rb +11 -0
  32. data/lib/gamefic/props/yes_or_no.rb +21 -0
  33. data/lib/gamefic/props.rb +10 -0
  34. data/lib/gamefic/query/base.rb +45 -126
  35. data/lib/gamefic/query/general.rb +46 -0
  36. data/lib/gamefic/query/result.rb +20 -0
  37. data/lib/gamefic/query/scoped.rb +41 -0
  38. data/lib/gamefic/query/text.rb +30 -31
  39. data/lib/gamefic/query.rb +7 -15
  40. data/lib/gamefic/response.rb +118 -0
  41. data/lib/gamefic/rulebook/calls.rb +90 -0
  42. data/lib/gamefic/rulebook/events.rb +79 -0
  43. data/lib/gamefic/rulebook/hooks.rb +57 -0
  44. data/lib/gamefic/rulebook/scenes.rb +68 -0
  45. data/lib/gamefic/rulebook.rb +139 -0
  46. data/lib/gamefic/scanner.rb +103 -0
  47. data/lib/gamefic/scene/activity.rb +9 -17
  48. data/lib/gamefic/scene/conclusion.rb +6 -5
  49. data/lib/gamefic/scene/default.rb +88 -0
  50. data/lib/gamefic/scene/multiple_choice.rb +14 -69
  51. data/lib/gamefic/scene/pause.rb +9 -13
  52. data/lib/gamefic/scene/yes_or_no.rb +6 -46
  53. data/lib/gamefic/scene.rb +11 -7
  54. data/lib/gamefic/scope/base.rb +44 -0
  55. data/lib/gamefic/scope/children.rb +16 -0
  56. data/lib/gamefic/scope/family.rb +20 -0
  57. data/lib/gamefic/scope/myself.rb +13 -0
  58. data/lib/gamefic/scope/parent.rb +13 -0
  59. data/lib/gamefic/scope/siblings.rb +14 -0
  60. data/lib/gamefic/scope.rb +8 -0
  61. data/lib/gamefic/scriptable/actions.rb +156 -0
  62. data/lib/gamefic/scriptable/entities.rb +76 -0
  63. data/lib/gamefic/scriptable/events.rb +65 -0
  64. data/lib/gamefic/scriptable/proxy.rb +55 -0
  65. data/lib/gamefic/scriptable/queries.rb +73 -0
  66. data/lib/gamefic/scriptable/scenes.rb +162 -0
  67. data/lib/gamefic/scriptable.rb +167 -73
  68. data/lib/gamefic/snapshot.rb +36 -0
  69. data/lib/gamefic/stage.rb +51 -0
  70. data/lib/gamefic/subplot.rb +51 -79
  71. data/lib/gamefic/syntax/template.rb +67 -0
  72. data/lib/gamefic/syntax.rb +102 -83
  73. data/lib/gamefic/vault.rb +50 -0
  74. data/lib/gamefic/version.rb +1 -1
  75. data/lib/gamefic.rb +26 -15
  76. data/spec-opal/spec_helper.rb +24 -0
  77. metadata +91 -29
  78. data/lib/gamefic/element.rb +0 -46
  79. data/lib/gamefic/keywords.rb +0 -52
  80. data/lib/gamefic/messaging.rb +0 -43
  81. data/lib/gamefic/plot/darkroom.rb +0 -120
  82. data/lib/gamefic/plot/host.rb +0 -42
  83. data/lib/gamefic/plot/snapshot.rb +0 -27
  84. data/lib/gamefic/query/children.rb +0 -9
  85. data/lib/gamefic/query/descendants.rb +0 -15
  86. data/lib/gamefic/query/external.rb +0 -39
  87. data/lib/gamefic/query/family.rb +0 -18
  88. data/lib/gamefic/query/itself.rb +0 -13
  89. data/lib/gamefic/query/matches.rb +0 -75
  90. data/lib/gamefic/query/parent.rb +0 -9
  91. data/lib/gamefic/query/siblings.rb +0 -13
  92. data/lib/gamefic/query/tree.rb +0 -17
  93. data/lib/gamefic/scene/base.rb +0 -142
  94. data/lib/gamefic/scene/multiple_scene.rb +0 -29
  95. data/lib/gamefic/serialize.rb +0 -196
  96. data/lib/gamefic/world/callbacks.rb +0 -135
  97. data/lib/gamefic/world/commands.rb +0 -181
  98. data/lib/gamefic/world/entities.rb +0 -98
  99. data/lib/gamefic/world/playbook.rb +0 -233
  100. data/lib/gamefic/world/players.rb +0 -37
  101. data/lib/gamefic/world/scenes.rb +0 -228
  102. data/lib/gamefic/world.rb +0 -18
@@ -1,72 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'gamefic/syntax/template'
4
+
1
5
  module Gamefic
6
+ # Syntaxes provide rules for matching input patterns to existing responses.
7
+ # Common uses are to provide synonyms for response verbs and allow for
8
+ # variations in sentence structure.
9
+ #
10
+ # The template and command patterns use words beginning with a colon (e.g.,
11
+ # `:thing`) to identify phrases that should be tokenized into arguments.
12
+ #
13
+ # @example All of these syntaxes will translate input into a command of the
14
+ # form "look thing container"
15
+ #
16
+ # Syntax.new('examine :thing in :container', 'look :thing :container')
17
+ # Syntax.new('look at :thing inside :container', 'look :thing :container')
18
+ # Syntax.new('search :container for :thing', 'look :thing :container')
19
+ #
2
20
  class Syntax
3
- attr_reader :token_count, :first_word, :verb, :template, :command
21
+ # The pattern that matching input is expected to follow.
22
+ #
23
+ # @return [Template]
24
+ attr_reader :template
25
+
26
+ # The pattern that will be used to tokenize the input into a command.
27
+ #
28
+ # @return [String]
29
+ attr_reader :command
30
+
31
+ # The response verb to which the command will be translated.
32
+ #
33
+ # @example
34
+ # syntax = Syntax.new('examine :thing', 'look :thing')
35
+ # syntax.verb #=> :look
36
+ #
37
+ # @return [Symbol]
38
+ attr_reader :verb
4
39
 
40
+ # @param template [Template, String]
41
+ # @param command [String]
5
42
  def initialize template, command
6
- words = template.split_words
7
- @token_count = words.length
8
- command_words = command.split_words
9
- @verb = nil
10
- if words[0][0] == ':'
11
- @token_count -= 1
12
- @first_word = ''
13
- else
14
- @first_word = words[0].to_s
15
- @verb = command_words[0].to_sym
16
- end
17
- @command = command_words.join(' ')
18
- @template = words.join(' ')
19
- tokens = []
20
- variable_tokens = []
21
- last_token_is_reg = false
22
- words.each { |w|
23
- if w.match(/^:[a-z0-9_]+$/i)
24
- variable_tokens.push w
25
- if last_token_is_reg
26
- next
27
- else
28
- tokens.push '([\w\W\s\S]*?)'
29
- last_token_is_reg = true
30
- end
31
- else
32
- tokens.push w
33
- last_token_is_reg = false
34
- end
35
- }
36
- subs = []
37
- index = 0
38
- command_words.each { |t|
39
- if t[0] == ':'
40
- index = variable_tokens.index(t) + 1
41
- subs.push "{$#{index}}"
42
- else
43
- subs.push t
44
- end
45
- }
46
- @replace = subs.join(' ')
47
- @regexp = Regexp.new("^#{tokens.join(' ')}$", Regexp::IGNORECASE)
43
+ @template = Template.to_template(template)
44
+ @command = command.normalize
45
+ @verb = Syntax.literal_or_nil(@command.keywords[0])
46
+ @replace = parse_replace
47
+ end
48
+
49
+ # A symbol for the first word in the template. Used by rulebooks to
50
+ # classify groups of related syntaxes.
51
+ #
52
+ # @example
53
+ # syntax = Syntax.new('examine :thing', 'look :thing')
54
+ # syntax.synonym #=> :examine
55
+ #
56
+ # @return [Symbol]
57
+ def synonym
58
+ template.verb
48
59
  end
49
60
 
50
61
  # Convert a String into a Command.
51
62
  #
52
63
  # @param text [String]
53
- # @return [Gamefic::Command]
64
+ # @return [Command, nil]
54
65
  def tokenize text
55
- m = text.match(@regexp)
56
- return nil if m.nil?
57
- arguments = []
58
- b = @verb.nil? ? 0 : 1
59
- xverb = @verb
60
- @replace.to_s.split_words[b..-1].each { |r|
61
- if r.match(/^\{\$[0-9]+\}$/)
62
- arguments.push m[r[2..-2].to_i]
63
- elsif arguments.empty? && xverb.nil?
64
- xverb = r.to_sym
65
- else
66
- arguments.push r
67
- end
68
- }
69
- Command.new xverb, arguments
66
+ match = text&.match(template.regexp)
67
+ return nil unless match
68
+
69
+ Command.new(verb, match_to_args(match))
70
70
  end
71
71
 
72
72
  # Determine if the specified text matches the syntax's expected pattern.
@@ -74,47 +74,66 @@ module Gamefic
74
74
  # @param text [String]
75
75
  # @return [Boolean]
76
76
  def accept? text
77
- !text.match(@regexp).nil?
77
+ !!text.match(template.regexp)
78
78
  end
79
79
 
80
80
  # Get a signature that identifies the form of the Syntax.
81
81
  # Signatures are used to compare Syntaxes to each other.
82
82
  #
83
83
  def signature
84
- [@regexp, @replace]
84
+ [template.regexp, replace]
85
85
  end
86
86
 
87
87
  def ==(other)
88
- return false unless other.is_a?(Syntax)
89
- signature == other.signature
90
- end
91
-
92
- def eql?(other)
93
- self == other
88
+ signature == other&.signature
94
89
  end
95
90
 
96
- def hash
97
- signature.hash
98
- end
99
-
100
- # Tokenize an Array of Commands from the specified text. The resulting
101
- # array is in descending order of specificity, i.e., most to least matched
91
+ # Tokenize an array of commands from the specified text. The resulting
92
+ # array is in descending order of precision, i.e., most to least matched
102
93
  # tokens.
103
94
  #
104
95
  # @param text [String] The text to tokenize.
105
- # @param syntaxes [Array<Gamefic::Syntax>] The Syntaxes to use.
106
- # @return [Array<Gamefic::Command>] The tokenized commands.
96
+ # @param syntaxes [Array<Syntax>] The syntaxes to use.
97
+ # @return [Array<Command>] The tokenized commands.
107
98
  def self.tokenize text, syntaxes
108
99
  syntaxes
109
100
  .map { |syn| syn.tokenize(text) }
110
- .reject(&:nil?)
111
- .sort do |a, b|
112
- if a.arguments.length == b.arguments.length
113
- b.verb.to_s <=> a.verb.to_s
114
- else
115
- b.arguments.length <=> a.arguments.length
116
- end
117
- end
101
+ .compact
102
+ .sort { |syn, other_syn| syn.compare other_syn }
103
+ end
104
+
105
+ # Compare two syntaxes for the purpose of ordering them in rulebooks.
106
+ #
107
+ def compare other
108
+ template.compare other.template
109
+ end
110
+
111
+ # @param string [String]
112
+ # @return [String, nil]
113
+ def self.literal_or_nil string
114
+ string.start_with?(':') ? nil : string.to_sym
115
+ end
116
+
117
+ private
118
+
119
+ # @return [String]
120
+ attr_reader :replace
121
+
122
+ def parse_replace
123
+ command.keywords.map do |word|
124
+ next word unless word.start_with?(':')
125
+
126
+ index = template.params.index(word) ||
127
+ raise(ArgumentError, "syntax command references undefined parameter `#{word}`")
128
+ "{$#{index + 1}}"
129
+ end.join(' ')
130
+ end
131
+
132
+ def match_to_args match
133
+ start = replace.start_with?('{') ? 0 : 1
134
+ replace.keywords[start..].map do |str|
135
+ str.match?(/^\{\$[0-9]+\}$/) ? match[str[2..-2].to_i] : str
136
+ end
118
137
  end
119
138
  end
120
139
  end
@@ -0,0 +1,50 @@
1
+ module Gamefic
2
+ # An array wrapper that exposes a protected interface. The array is always
3
+ # returned frozen. It can only be modified through #add and #delete. The
4
+ # vault can be "locked" to prevent existing elements from being deleted.
5
+ #
6
+ class Vault
7
+ def initialize
8
+ @set = Set.new
9
+ @array = []
10
+ @lock_index = nil
11
+ end
12
+
13
+ # @return [Array]
14
+ def array
15
+ @array.freeze
16
+ end
17
+
18
+ # @param object [Object]
19
+ def add object
20
+ @array = @set.add(object).to_a
21
+ object
22
+ end
23
+
24
+ # @param object [Object]
25
+ # @return [Boolean] True if object was deleted
26
+ def delete object
27
+ return false unless deletable?(object) && @set.delete?(object)
28
+
29
+ @array = @set.to_a.freeze
30
+ true
31
+ end
32
+
33
+ # Lock the current elements in the vault.
34
+ #
35
+ # After the vault is locked, calling #delete on a locked element will leave
36
+ # the element in the array and return false. Elements added after the lock
37
+ # can be deleted.
38
+ #
39
+ def lock
40
+ return @lock_index if @lock_index
41
+
42
+ @lock_index = @array.length
43
+ end
44
+
45
+ # @return [Boolean] True if the object is deletable (i.e., not locked).
46
+ def deletable? object
47
+ @lock_index.to_i <= @array.find_index(object).to_i
48
+ end
49
+ end
50
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Gamefic
4
- VERSION = '2.4.0'
4
+ VERSION = '3.0.0'
5
5
  end
data/lib/gamefic.rb CHANGED
@@ -1,22 +1,33 @@
1
- require 'gamefic/version'
1
+ # frozen_string_literal: true
2
2
 
3
- require 'gamefic/keywords'
3
+ require 'json'
4
+ require 'gamefic/version'
5
+ require 'gamefic/logging'
4
6
  require 'gamefic/core_ext/array'
5
7
  require 'gamefic/core_ext/string'
6
-
8
+ require 'gamefic/syntax'
9
+ require 'gamefic/response'
10
+ require 'gamefic/rulebook'
11
+ require 'gamefic/query'
12
+ require 'gamefic/scanner'
13
+ require 'gamefic/scope'
14
+ require 'gamefic/command'
15
+ require 'gamefic/action'
16
+ require 'gamefic/props'
17
+ require 'gamefic/scene'
18
+ require 'gamefic/scriptable'
19
+ require 'gamefic/block'
20
+ require 'gamefic/stage'
21
+ require 'gamefic/vault'
22
+ require 'gamefic/narrative'
23
+ require 'gamefic/plot'
24
+ require 'gamefic/subplot'
25
+ require 'gamefic/snapshot'
26
+ require 'gamefic/node'
7
27
  require 'gamefic/describable'
8
- require 'gamefic/serialize'
9
- require 'gamefic/element'
28
+ require 'gamefic/messenger'
10
29
  require 'gamefic/entity'
30
+ require 'gamefic/dispatcher'
11
31
  require 'gamefic/active'
32
+ require 'gamefic/active/cue'
12
33
  require 'gamefic/actor'
13
- require "gamefic/scene"
14
- require "gamefic/query"
15
- require "gamefic/action"
16
- require "gamefic/syntax"
17
- require "gamefic/command"
18
- require "gamefic/dispatcher"
19
- require 'gamefic/world'
20
- require 'gamefic/scriptable'
21
- require 'gamefic/plot'
22
- require 'gamefic/subplot'
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'gamefic'
4
+ require 'ostruct'
5
+
6
+ RSpec.configure do |config|
7
+ # Run specs in random order to surface order dependencies. If you find an
8
+ # order dependency and want to debug it, you can fix the order by providing
9
+ # the seed, which is printed after each run.
10
+ # --seed 1234
11
+ # config.order = :random
12
+
13
+ # Seed global randomization in this process using the `--seed` CLI option.
14
+ # Setting this allows you to use `--seed` to deterministically reproduce
15
+ # test failures related to randomization by passing the same `--seed` value
16
+ # as the one that triggered the failure.
17
+ # Kernel.srand config.seed
18
+
19
+ config.after :each do
20
+ Gamefic::Narrative.blocks.clear
21
+ Gamefic::Plot.blocks.clear
22
+ Gamefic::Subplot.blocks.clear
23
+ end
24
+ end
metadata CHANGED
@@ -1,15 +1,57 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gamefic
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.4.0
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Fred Snyder
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-02-11 00:00:00.000000000 Z
11
+ date: 2024-01-27 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: opal
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: opal-rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: opal-sprockets
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.0'
13
55
  - !ruby/object:Gem::Dependency
14
56
  name: rake
15
57
  requirement: !ruby/object:Gem::Requirement
@@ -73,6 +115,7 @@ files:
73
115
  - ".github/workflows/rspec.yml"
74
116
  - ".gitignore"
75
117
  - ".rspec"
118
+ - ".rspec-opal"
76
119
  - ".rubocop.yml"
77
120
  - ".solargraph.yml"
78
121
  - CHANGELOG.md
@@ -80,58 +123,77 @@ files:
80
123
  - LICENSE
81
124
  - README.md
82
125
  - Rakefile
126
+ - bin/console
127
+ - bin/setup
83
128
  - gamefic.gemspec
84
129
  - lib/gamefic.rb
85
130
  - lib/gamefic/action.rb
86
131
  - lib/gamefic/active.rb
132
+ - lib/gamefic/active/cue.rb
133
+ - lib/gamefic/active/epic.rb
134
+ - lib/gamefic/active/messaging.rb
135
+ - lib/gamefic/active/take.rb
87
136
  - lib/gamefic/actor.rb
137
+ - lib/gamefic/block.rb
88
138
  - lib/gamefic/command.rb
89
139
  - lib/gamefic/core_ext/array.rb
90
140
  - lib/gamefic/core_ext/string.rb
91
141
  - lib/gamefic/describable.rb
92
142
  - lib/gamefic/dispatcher.rb
93
- - lib/gamefic/element.rb
94
143
  - lib/gamefic/entity.rb
95
- - lib/gamefic/keywords.rb
96
- - lib/gamefic/messaging.rb
144
+ - lib/gamefic/logging.rb
145
+ - lib/gamefic/messenger.rb
146
+ - lib/gamefic/narrative.rb
97
147
  - lib/gamefic/node.rb
98
148
  - lib/gamefic/plot.rb
99
- - lib/gamefic/plot/darkroom.rb
100
- - lib/gamefic/plot/host.rb
101
- - lib/gamefic/plot/snapshot.rb
149
+ - lib/gamefic/props.rb
150
+ - lib/gamefic/props/default.rb
151
+ - lib/gamefic/props/multiple_choice.rb
152
+ - lib/gamefic/props/pause.rb
153
+ - lib/gamefic/props/yes_or_no.rb
102
154
  - lib/gamefic/query.rb
103
155
  - lib/gamefic/query/base.rb
104
- - lib/gamefic/query/children.rb
105
- - lib/gamefic/query/descendants.rb
106
- - lib/gamefic/query/external.rb
107
- - lib/gamefic/query/family.rb
108
- - lib/gamefic/query/itself.rb
109
- - lib/gamefic/query/matches.rb
110
- - lib/gamefic/query/parent.rb
111
- - lib/gamefic/query/siblings.rb
156
+ - lib/gamefic/query/general.rb
157
+ - lib/gamefic/query/result.rb
158
+ - lib/gamefic/query/scoped.rb
112
159
  - lib/gamefic/query/text.rb
113
- - lib/gamefic/query/tree.rb
160
+ - lib/gamefic/response.rb
161
+ - lib/gamefic/rulebook.rb
162
+ - lib/gamefic/rulebook/calls.rb
163
+ - lib/gamefic/rulebook/events.rb
164
+ - lib/gamefic/rulebook/hooks.rb
165
+ - lib/gamefic/rulebook/scenes.rb
166
+ - lib/gamefic/scanner.rb
114
167
  - lib/gamefic/scene.rb
115
168
  - lib/gamefic/scene/activity.rb
116
- - lib/gamefic/scene/base.rb
117
169
  - lib/gamefic/scene/conclusion.rb
170
+ - lib/gamefic/scene/default.rb
118
171
  - lib/gamefic/scene/multiple_choice.rb
119
- - lib/gamefic/scene/multiple_scene.rb
120
172
  - lib/gamefic/scene/pause.rb
121
173
  - lib/gamefic/scene/yes_or_no.rb
174
+ - lib/gamefic/scope.rb
175
+ - lib/gamefic/scope/base.rb
176
+ - lib/gamefic/scope/children.rb
177
+ - lib/gamefic/scope/family.rb
178
+ - lib/gamefic/scope/myself.rb
179
+ - lib/gamefic/scope/parent.rb
180
+ - lib/gamefic/scope/siblings.rb
122
181
  - lib/gamefic/scriptable.rb
123
- - lib/gamefic/serialize.rb
182
+ - lib/gamefic/scriptable/actions.rb
183
+ - lib/gamefic/scriptable/entities.rb
184
+ - lib/gamefic/scriptable/events.rb
185
+ - lib/gamefic/scriptable/proxy.rb
186
+ - lib/gamefic/scriptable/queries.rb
187
+ - lib/gamefic/scriptable/scenes.rb
188
+ - lib/gamefic/snapshot.rb
189
+ - lib/gamefic/stage.rb
124
190
  - lib/gamefic/subplot.rb
125
191
  - lib/gamefic/syntax.rb
192
+ - lib/gamefic/syntax/template.rb
193
+ - lib/gamefic/vault.rb
126
194
  - lib/gamefic/version.rb
127
- - lib/gamefic/world.rb
128
- - lib/gamefic/world/callbacks.rb
129
- - lib/gamefic/world/commands.rb
130
- - lib/gamefic/world/entities.rb
131
- - lib/gamefic/world/playbook.rb
132
- - lib/gamefic/world/players.rb
133
- - lib/gamefic/world/scenes.rb
134
- homepage: http://gamefic.com
195
+ - spec-opal/spec_helper.rb
196
+ homepage: https://gamefic.com
135
197
  licenses:
136
198
  - MIT
137
199
  metadata: {}
@@ -143,7 +205,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
143
205
  requirements:
144
206
  - - ">="
145
207
  - !ruby/object:Gem::Version
146
- version: 2.3.0
208
+ version: 2.7.0
147
209
  required_rubygems_version: !ruby/object:Gem::Requirement
148
210
  requirements:
149
211
  - - ">="
@@ -1,46 +0,0 @@
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::Serialize
11
-
12
- def initialize(args = {})
13
- klass = self.class
14
- defaults = {}
15
- while klass <= Element
16
- defaults = klass.default_attributes.merge(defaults)
17
- klass = klass.superclass
18
- end
19
- defaults.merge(args).each_pair do |k, v|
20
- public_send "#{k}=", v
21
- end
22
- post_initialize
23
- yield self if block_given?
24
- end
25
-
26
- def post_initialize
27
- # raise NotImplementedError, "#{self.class} must implement post_initialize"
28
- end
29
-
30
- class << self
31
- # Set or update the default values for new instances.
32
- #
33
- # @param attrs [Hash] The attributes to be merged into the defaults.
34
- def set_default attrs = {}
35
- default_attributes.merge! attrs
36
- end
37
-
38
- # A hash of default values for attributes when creating an instance.
39
- #
40
- # @return [Hash]
41
- def default_attributes
42
- @default_attributes ||= {}
43
- end
44
- end
45
- end
46
- end
@@ -1,52 +0,0 @@
1
- module Gamefic
2
- module Keywords
3
- SPLIT_REGEXP = /[\s]+/
4
-
5
- # Get an array of keywords associated with this object.
6
- # The default implementation splits the value of self.to_s into an array.
7
- #
8
- # @return [Array<String>]
9
- def keywords
10
- self.to_s.downcase.split(SPLIT_REGEXP).uniq
11
- end
12
-
13
- # Determine if this object matches the provided description.
14
- # In a regular match, every word in the description must be a keyword.
15
- # Fuzzy matches accept words if a keyword starts with it, e.g., "red"
16
- # would be a fuzzy match for "reddish."
17
- #
18
- # @example
19
- # dog = "big red dog"
20
- # dog.extend Gamefic::Matchable
21
- #
22
- # dog.specified?("red dog") #=> true
23
- # dog.specified?("gray dog") #=> false
24
- # dog.specified?("red do") #=> false
25
- #
26
- # dog.specified?("re do", fuzzy: true) #=> true
27
- # dog.specified?("red og", fuzzy: true) #=> false
28
- #
29
- # @param description [String] The description to be compared
30
- # @param fuzzy [Boolean] Use fuzzy matching (default is false)
31
- # @return [Boolean]
32
- def specified? description, fuzzy: false
33
- words = description.split(SPLIT_REGEXP)
34
- return false if words.empty?
35
- matches = 0
36
- available = keywords
37
- words.each { |w|
38
- if fuzzy
39
- available.each { |k|
40
- if k.gsub(/[^a-z0-9]/, '').start_with?(w.downcase.gsub(/[^a-z0-9]/, ''))
41
- matches +=1
42
- break
43
- end
44
- }
45
- else
46
- matches +=1 if available.include?(w.downcase)
47
- end
48
- }
49
- matches == words.length
50
- end
51
- end
52
- end
@@ -1,43 +0,0 @@
1
- module Gamefic
2
- module Messaging
3
- # Send a message to the entity.
4
- # This method will automatically wrap the message in HTML paragraphs.
5
- # To send a message without paragraph formatting, use #stream instead.
6
- #
7
- # @param message [String]
8
- def tell(message)
9
- @messages = @messages.to_s + format(message)
10
- end
11
-
12
- # Send a message to the Character as raw text.
13
- # Unlike #tell, this method will not wrap the message in HTML paragraphs.
14
- #
15
- # @param message [String]
16
- def stream(message)
17
- @messages = @messages.to_s + message
18
- end
19
-
20
- # Get all the currently buffered messages consolidated in a single string.
21
- #
22
- # @return [String]
23
- def messages
24
- @messages ||= ''
25
- end
26
-
27
- # Clear the buffered messages.
28
- #
29
- def flush
30
- @messages = ''
31
- end
32
-
33
- private
34
-
35
- def format message
36
- "<p>#{message.strip}</p>"
37
- .gsub(/[ \t\r]*\n[ \t\r]*\n[ \t\r]*/, "</p><p>")
38
- .gsub(/[ \t]*\n[ \t]*/, ' ')
39
- .gsub(/<p>[\s]*<p>/, '<p>')
40
- .gsub(/<\/p>[\s]*<\/p>/, '</p>')
41
- end
42
- end
43
- end