gamefic 1.7.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +12 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +16 -0
  5. data/.solargraph.yml +5 -0
  6. data/CHANGELOG.md +10 -0
  7. data/Gemfile +7 -0
  8. data/LICENSE +20 -0
  9. data/README.md +28 -0
  10. data/Rakefile +10 -0
  11. data/gamefic.gemspec +27 -0
  12. data/lib/gamefic.rb +7 -7
  13. data/lib/gamefic/action.rb +66 -60
  14. data/lib/gamefic/active.rb +331 -280
  15. data/lib/gamefic/actor.rb +8 -5
  16. data/lib/gamefic/command.rb +9 -7
  17. data/lib/gamefic/core_ext/array.rb +27 -49
  18. data/lib/gamefic/core_ext/string.rb +25 -16
  19. data/lib/gamefic/describable.rb +21 -23
  20. data/lib/gamefic/element.rb +47 -31
  21. data/lib/gamefic/entity.rb +6 -12
  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 -91
  26. data/lib/gamefic/plot/darkroom.rb +80 -264
  27. data/lib/gamefic/plot/host.rb +42 -48
  28. data/lib/gamefic/plot/snapshot.rb +14 -19
  29. data/lib/gamefic/query.rb +15 -18
  30. data/lib/gamefic/query/base.rb +50 -37
  31. data/lib/gamefic/query/children.rb +0 -0
  32. data/lib/gamefic/query/descendants.rb +2 -2
  33. data/lib/gamefic/query/external.rb +18 -14
  34. data/lib/gamefic/query/family.rb +3 -7
  35. data/lib/gamefic/query/matches.rb +75 -67
  36. data/lib/gamefic/query/parent.rb +0 -0
  37. data/lib/gamefic/query/siblings.rb +0 -0
  38. data/lib/gamefic/query/text.rb +12 -12
  39. data/lib/gamefic/query/tree.rb +17 -0
  40. data/lib/gamefic/scene.rb +0 -2
  41. data/lib/gamefic/scene/activity.rb +24 -26
  42. data/lib/gamefic/scene/base.rb +71 -10
  43. data/lib/gamefic/scene/conclusion.rb +1 -3
  44. data/lib/gamefic/scene/multiple_choice.rb +19 -14
  45. data/lib/gamefic/scene/multiple_scene.rb +29 -20
  46. data/lib/gamefic/scene/pause.rb +8 -3
  47. data/lib/gamefic/scene/yes_or_no.rb +22 -10
  48. data/lib/gamefic/scriptable.rb +88 -0
  49. data/lib/gamefic/serialize.rb +223 -0
  50. data/lib/gamefic/subplot.rb +38 -35
  51. data/lib/gamefic/syntax.rb +15 -13
  52. data/lib/gamefic/version.rb +3 -3
  53. data/lib/gamefic/world.rb +18 -0
  54. data/lib/gamefic/world/callbacks.rb +135 -0
  55. data/lib/gamefic/world/commands.rb +184 -0
  56. data/lib/gamefic/{plot → world}/entities.rb +33 -35
  57. data/lib/gamefic/{plot → world}/playbook.rb +245 -240
  58. data/lib/gamefic/world/players.rb +37 -0
  59. data/lib/gamefic/world/scenes.rb +226 -0
  60. metadata +37 -88
  61. data/bin/gamefic +0 -9
  62. data/lib/gamefic/engine.rb +0 -7
  63. data/lib/gamefic/engine/base.rb +0 -59
  64. data/lib/gamefic/engine/tty.rb +0 -24
  65. data/lib/gamefic/grammar.rb +0 -13
  66. data/lib/gamefic/grammar/conjugator.rb +0 -20
  67. data/lib/gamefic/grammar/gender.rb +0 -11
  68. data/lib/gamefic/grammar/person.rb +0 -10
  69. data/lib/gamefic/grammar/plural.rb +0 -13
  70. data/lib/gamefic/grammar/pronouns.rb +0 -106
  71. data/lib/gamefic/grammar/tense.rb +0 -6
  72. data/lib/gamefic/grammar/verb_set.rb +0 -43
  73. data/lib/gamefic/grammar/verbs.rb +0 -26
  74. data/lib/gamefic/grammar/word_adapter.rb +0 -49
  75. data/lib/gamefic/plot/articles.rb +0 -22
  76. data/lib/gamefic/plot/callbacks.rb +0 -126
  77. data/lib/gamefic/plot/commands.rb +0 -120
  78. data/lib/gamefic/plot/players.rb +0 -15
  79. data/lib/gamefic/plot/scenes.rb +0 -187
  80. data/lib/gamefic/plot/theater.rb +0 -73
  81. data/lib/gamefic/plot/you_mount.rb +0 -22
  82. data/lib/gamefic/scene/custom.rb +0 -9
  83. data/lib/gamefic/script.rb +0 -13
  84. data/lib/gamefic/script/base.rb +0 -42
  85. data/lib/gamefic/script/file.rb +0 -14
  86. data/lib/gamefic/script/text.rb +0 -14
  87. data/lib/gamefic/shell.rb +0 -76
  88. data/lib/gamefic/source.rb +0 -14
  89. data/lib/gamefic/source/base.rb +0 -12
  90. data/lib/gamefic/source/file.rb +0 -23
  91. data/lib/gamefic/source/text.rb +0 -16
  92. data/lib/gamefic/tester.rb +0 -19
  93. data/lib/gamefic/text.rb +0 -8
  94. data/lib/gamefic/text/ansi.rb +0 -53
  95. data/lib/gamefic/text/html.rb +0 -68
  96. data/lib/gamefic/text/html/conversions.rb +0 -250
  97. data/lib/gamefic/text/html/entities.rb +0 -9
  98. data/lib/gamefic/tty.rb +0 -10
  99. data/lib/gamefic/user.rb +0 -7
  100. data/lib/gamefic/user/base.rb +0 -29
  101. data/lib/gamefic/user/tty.rb +0 -38
@@ -1,250 +0,0 @@
1
- require 'gamefic/text/ansi'
2
- require 'gamefic/text/html'
3
- require 'io/console'
4
-
5
- module Gamefic
6
-
7
- module Text::Html::Conversions
8
- include Gamefic::Text
9
-
10
- def self.html_to_ansi text, wrap: true, width: nil
11
- return '' if text.strip == ''
12
- output = ''
13
- begin
14
- doc = Html.parse("<body>#{text.gsub(/\r/, '').strip}</body>")
15
- output = AnsiFormatter.new.format(doc) + Ansi.graphics_mode(Ansi::Code::Attribute::NORMAL)
16
- output = Html.decode(output)
17
- rescue REXML::ParseException => e
18
- output = text.strip
19
- end
20
- calc_width = width || size[0]
21
- if calc_width.nil? or !wrap
22
- output
23
- else
24
- terminalize(output, calc_width - 1)
25
- end
26
- end
27
-
28
- def self.html_to_text text, wrap: true, width: nil
29
- text = html_to_ansi text, wrap: wrap, width: width
30
- text.gsub(/\e\[([;\d]+)?m/, '').gsub(/\n +\n/, "\n\n")
31
- end
32
-
33
- class AnsiNode
34
- include Gamefic::Text::Ansi::Code
35
- attr_accessor :parent
36
-
37
- def render
38
- end
39
-
40
- def in_block?
41
- p = parent
42
- while !p.nil?
43
- return true if p.kind_of?(BlockNode)
44
- p = p.parent
45
- end
46
- false
47
- end
48
- end
49
- private_constant :AnsiNode
50
-
51
- class TextNode < AnsiNode
52
- @@prev_format = nil
53
- attr_reader :text, :format
54
- def initialize text, format
55
- @text = text
56
- @format = format
57
- end
58
- def render
59
- return @text if format.include?(Extra::PRE)
60
- index = parent.children.index(self)
61
- if index > 0
62
- prev = parent.children[index - 1]
63
- if prev.kind_of?(TextNode) and prev.format == format
64
- if prev.text.match(/ $/)
65
- return @text.lstrip
66
- else
67
- return @text
68
- end
69
- end
70
- end
71
- if @@prev_format == format
72
- @text
73
- else
74
- @prev_format = format
75
- Gamefic::Text::Ansi.graphics_mode(*format) + @text
76
- end
77
- end
78
- end
79
- private_constant :TextNode
80
-
81
- class ElementNode < AnsiNode
82
- def children
83
- @children ||= []
84
- end
85
- def append child
86
- children.push child
87
- child.parent = self
88
- end
89
- end
90
- private_constant :ElementNode
91
-
92
- class BlockNode < ElementNode
93
- def render
94
- output = ''
95
- children.each { |c|
96
- output += c.render
97
- }
98
- output = "\n" + output.strip unless in_block?
99
- output
100
- end
101
- end
102
- private_constant :BlockNode
103
-
104
- class InlineNode < ElementNode
105
- def render
106
- output = ''
107
- children.each { |c|
108
- output += c.render
109
- output += "\n" if c.kind_of?(BlockNode)
110
- }
111
- output
112
- end
113
- end
114
- private_constant :InlineNode
115
-
116
- class BreakNode < ElementNode
117
- def render
118
- output = ''
119
- children.each { |c|
120
- output += c.render
121
- }
122
- output + "\n"
123
- end
124
- end
125
- private_constant :BreakNode
126
-
127
- class AnsiFormatter
128
- include Gamefic::Text::Ansi::Code
129
- def format document
130
- @document = document
131
- @ansi_root = InlineNode.new
132
- @list_index = []
133
- format_recursively @document.root, @ansi_root, [Attribute::NORMAL]
134
- output = @ansi_root.render
135
- output += (@ansi_root.children.last.kind_of?(BlockNode) ? "\n" : "")
136
- end
137
-
138
- def format_recursively element, ansi_node, stack
139
- if element.is_a?(REXML::Text)
140
- append_text element, ansi_node, stack
141
- else
142
- current = []
143
- case element.name
144
- when 'b', 'strong', 'em'
145
- current.push Attribute::BOLD
146
- format_children element, ansi_node, stack + current
147
- when 'i', 'u'
148
- current.push Attribute::UNDERSCORE
149
- format_children element, ansi_node, stack + current
150
- when 'h1', 'h2', 'h3', 'h4', 'h5'
151
- current.push Attribute::BOLD, Extra::UPPERCASE
152
- format_paragraph element, ansi_node, stack + current
153
- when 'p'
154
- format_paragraph element, ansi_node, stack
155
- when 'ol', 'ul'
156
- @list_index.push 0
157
- format_paragraph element, ansi_node, stack
158
- @list_index.pop
159
- when 'li'
160
- format_list_item element, ansi_node, stack
161
- when 'pre'
162
- current.push Extra::PRE
163
- format_children element, ansi_node, stack + current
164
- when 'br'
165
- ansi_node.append TextNode.new("\n", stack + [Extra::PRE])
166
- else
167
- format_children element, ansi_node, stack
168
- end
169
- end
170
- end
171
-
172
- def append_text element, ansi_node, stack
173
- text = element.to_s
174
- text.gsub!(/[\s]+/, ' ') unless stack.include?(Extra::PRE)
175
- text.upcase! if stack.include?(Extra::UPPERCASE)
176
- ansi_node.append TextNode.new(text, stack)
177
- end
178
-
179
- def format_children element, node, stack
180
- element.each { |e|
181
- format_recursively e, node, stack
182
- }
183
- end
184
-
185
- def format_paragraph element, node, stack
186
- paragraph = BlockNode.new
187
- node.append paragraph
188
- format_children element, paragraph, stack
189
- end
190
-
191
- def format_list_item element, node, stack
192
- i = 0
193
- unless @list_index.empty?
194
- @list_index[-1] = @list_index[-1] + 1
195
- i = @list_index[-1]
196
- end
197
- b = BreakNode.new
198
- node.append b
199
- if element.parent.name == 'ol'
200
- b.append TextNode.new("#{i}. ", stack)
201
- else
202
- b.append TextNode.new("* ", stack)
203
- end
204
- format_children element, b, stack
205
- end
206
- end
207
- private_constant :AnsiFormatter
208
-
209
- def self.terminalize string, max_length
210
- i = 0
211
- output = ''
212
- line_length = 0
213
- while i < string.length
214
- line_length += 1
215
- char = string[i,1]
216
- if char == "\e"
217
- # Right now, graphics modes are the only supported ANSI sequences.
218
- end_of_seq = string.index("m", i)
219
- output += string[i..end_of_seq]
220
- i = end_of_seq + 1
221
- elsif char == " "
222
- next_space = string.index(/[\s]/, i + 1)
223
- if !next_space.nil? and line_length + (next_space - i) > max_length
224
- output += "\n"
225
- line_length = 0
226
- else
227
- output += char
228
- end
229
- i += 1
230
- else
231
- if char == "\n"
232
- line_length = 0
233
- end
234
- output += char
235
- i += 1
236
- end
237
- end
238
- output
239
- end
240
-
241
- def self.size
242
- begin
243
- return STDOUT.winsize.reverse
244
- rescue
245
- return [nil,nil]
246
- end
247
- end
248
- end
249
-
250
- end
@@ -1,9 +0,0 @@
1
- module Gamefic
2
-
3
- module Text
4
- module Html
5
- ENTITIES = { "&quot;" => "\"", "&amp;" => "&", "&lt;" => "<", "&gt;" => ">", "&nbsp;" => " ", "&iexcl;" => "¡", "&cent;" => "¢", "&pound;" => "£", "&curren;" => "¤", "&yen;" => "¥", "&brvbar;" => "¦", "&sect;" => "§", "&uml;" => "¨", "&copy;" => "©", "&ordf;" => "ª", "&laquo;" => "«", "&not;" => "¬", "&shy;" => "­", "&reg;" => "®", "&macr;" => "¯", "&deg;" => "°", "&plusmn;" => "±", "&sup2;" => "²", "&sup3;" => "³", "&acute;" => "´", "&micro;" => "µ", "&para;" => "¶", "&middot;" => "·", "&cedil;" => "¸", "&sup1;" => "¹", "&ordm;" => "º", "&raquo;" => "»", "&frac14;" => "¼", "&frac12;" => "½", "&frac34;" => "¾", "&iquest;" => "¿", "&Agrave;" => "À", "&Aacute;" => "Á", "&Acirc;" => "Â", "&Atilde;" => "Ã", "&Auml;" => "Ä", "&Aring;" => "Å", "&AElig;" => "Æ", "&Ccedil;" => "Ç", "&Egrave;" => "È", "&Eacute;" => "É", "&Ecirc;" => "Ê", "&Euml;" => "Ë", "&Igrave;" => "Ì", "&Iacute;" => "Í", "&Icirc;" => "Î", "&Iuml;" => "Ï", "&ETH;" => "Ð", "&Ntilde;" => "Ñ", "&Ograve;" => "Ò", "&Oacute;" => "Ó", "&Ocirc;" => "Ô", "&Otilde;" => "Õ", "&Ouml;" => "Ö", "&times;" => "×", "&Oslash;" => "Ø", "&Ugrave;" => "Ù", "&Uacute;" => "Ú", "&Ucirc;" => "Û", "&Uuml;" => "Ü", "&Yacute;" => "Ý", "&THORN;" => "Þ", "&szlig;" => "ß", "&agrave;" => "à", "&aacute;" => "á", "&acirc;" => "â", "&atilde;" => "ã", "&auml;" => "ä", "&aring;" => "å", "&aelig;" => "æ", "&ccedil;" => "ç", "&egrave;" => "è", "&eacute;" => "é", "&ecirc;" => "ê", "&euml;" => "ë", "&igrave;" => "ì", "&iacute;" => "í", "&icirc;" => "î", "&iuml;" => "ï", "&eth;" => "ð", "&ntilde;" => "ñ", "&ograve;" => "ò", "&oacute;" => "ó", "&ocirc;" => "ô", "&otilde;" => "õ", "&ouml;" => "ö", "&divide;" => "÷", "&oslash;" => "ø", "&ugrave;" => "ù", "&uacute;" => "ú", "&ucirc;" => "û", "&uuml;" => "ü", "&yacute;" => "ý", "&thorn;" => "þ", "&yuml;" => "ÿ", "&OElig;" => "Œ", "&oelig;" => "œ", "&Scaron;" => "Š", "&scaron;" => "š", "&Yuml;" => "Ÿ", "&fnof;" => "ƒ", "&circ;" => "ˆ", "&tilde;" => "˜", "&Alpha;" => "Α", "&Beta;" => "Β", "&Gamma;" => "Γ", "&Delta;" => "Δ", "&Epsilon;" => "Ε", "&Zeta;" => "Ζ", "&Eta;" => "Η", "&Theta;" => "Θ", "&Iota;" => "Ι", "&Kappa;" => "Κ", "&Lambda;" => "Λ", "&Mu;" => "Μ", "&Nu;" => "Ν", "&Xi;" => "Ξ", "&Omicron;" => "Ο", "&Pi;" => "Π", "&Rho;" => "Ρ", "&Sigma;" => "Σ", "&Tau;" => "Τ", "&Upsilon;" => "Υ", "&Phi;" => "Φ", "&Chi;" => "Χ", "&Psi;" => "Ψ", "&Omega;" => "Ω", "&alpha;" => "α", "&beta;" => "β", "&gamma;" => "γ", "&delta;" => "δ", "&epsilon;" => "ε", "&zeta;" => "ζ", "&eta;" => "η", "&theta;" => "θ", "&iota;" => "ι", "&kappa;" => "κ", "&lambda;" => "λ", "&mu;" => "μ", "&nu;" => "ν", "&xi;" => "ξ", "&omicron;" => "ο", "&pi;" => "π", "&rho;" => "ρ", "&sigmaf;" => "ς", "&sigma;" => "σ", "&tau;" => "τ", "&upsilon;" => "υ", "&phi;" => "φ", "&chi;" => "χ", "&psi;" => "ψ", "&omega;" => "ω", "&thetasym;" => "ϑ", "&upsih;" => "ϒ", "&piv;" => "ϖ", "&ensp;" => " ", "&emsp;" => " ", "&thinsp;" => " ", "&zwnj;" => "‌", "&zwj;" => "‍", "&lrm;" => "‎", "&rlm;" => "‏", "&ndash;" => "–", "&mdash;" => "—", "&lsquo;" => "‘", "&rsquo;" => "’", "&sbquo;" => "‚", "&ldquo;" => "“", "&rdquo;" => "”", "&bdquo;" => "„", "&dagger;" => "†", "&Dagger;" => "‡", "&bull;" => "•", "&hellip;" => "…", "&permil;" => "‰", "&prime;" => "′", "&Prime;" => "″", "&lsaquo;" => "‹", "&rsaquo;" => "›", "&oline;" => "‾", "&frasl;" => "⁄", "&euro;" => "€", "&image;" => "ℑ", "&weierp;" => "℘", "&real;" => "ℜ", "&trade;" => "™", "&alefsym;" => "ℵ", "&larr;" => "←", "&uarr;" => "↑", "&rarr;" => "→", "&darr;" => "↓", "&harr;" => "↔", "&crarr;" => "↵", "&lArr;" => "⇐", "&uArr;" => "⇑", "&rArr;" => "⇒", "&dArr;" => "⇓", "&hArr;" => "⇔", "&forall;" => "∀", "&part;" => "∂", "&exist;" => "∃", "&empty;" => "∅", "&nabla;" => "∇", "&isin;" => "∈", "&notin;" => "∉", "&ni;" => "∋", "&prod;" => "∏", "&sum;" => "∑", "&minus;" => "−", "&lowast;" => "∗", "&radic;" => "√", "&prop;" => "∝", "&infin;" => "∞", "&ang;" => "∠", "&and;" => "∧", "&or;" => "∨", "&cap;" => "∩", "&cup;" => "∪", "&int;" => "∫", "&there4;" => "∴", "&sim;" => "∼", "&cong;" => "≅", "&asymp;" => "≈", "&ne;" => "≠", "&equiv;" => "≡", "&le;" => "≤", "&ge;" => "≥", "&sub;" => "⊂", "&sup;" => "⊃", "&nsub;" => "⊄", "&sube;" => "⊆", "&supe;" => "⊇", "&oplus;" => "⊕", "&otimes;" => "⊗", "&perp;" => "⊥", "&sdot;" => "⋅", "&lceil;" => "⌈", "&rceil;" => "⌉", "&lfloor;" => "⌊", "&rfloor;" => "⌋", "&lang;" => "〈", "&rang;" => "〉", "&loz;" => "◊", "&spades;" => "♠", "&clubs;" => "♣", "&hearts;" => "♥", "&diams;" => "♦" }
6
- end
7
- end
8
-
9
- end
data/lib/gamefic/tty.rb DELETED
@@ -1,10 +0,0 @@
1
- require 'gamefic/text'
2
-
3
- module Gamefic
4
- module Engine
5
- autoload :Tty, 'gamefic/engine/tty'
6
- end
7
- module User
8
- autoload :Tty, 'gamefic/user/tty'
9
- end
10
- end
data/lib/gamefic/user.rb DELETED
@@ -1,7 +0,0 @@
1
- module Gamefic
2
-
3
- module User
4
- autoload :Base, 'gamefic/user/base'
5
- end
6
-
7
- end
@@ -1,29 +0,0 @@
1
- module Gamefic
2
- class User::Base
3
- # @return [Gamefic::Active]
4
- attr_reader :character
5
-
6
- # @return [Gamefic::Engine::Base]
7
- attr_reader :engine
8
-
9
- def initialize engine
10
- @engine = engine
11
- end
12
-
13
- def connect entity
14
- @character = entity
15
- end
16
-
17
- def update state
18
- raise 'Unimplemented'
19
- end
20
-
21
- def save filename, snapshot
22
- raise 'Unimplemented'
23
- end
24
-
25
- def restore filename
26
- raise 'Unimplemented'
27
- end
28
- end
29
- end
@@ -1,38 +0,0 @@
1
- require 'gamefic/engine'
2
- require 'json'
3
- require 'gamefic/text'
4
-
5
- module Gamefic
6
-
7
- # Extend User::Base to convert HTML into ANSI text.
8
- #
9
- # @note Due to their dependency on io/console, User::Tty and Engine::Tty are
10
- # not included in the core Gamefic library. `require gamefic/tty` if you
11
- # need them.
12
- #
13
- class User::Tty < User::Base
14
- def update
15
- unless character.state[:options].nil?
16
- list = '<ol class="multiple_choice">'
17
- character.state[:options].each { |o|
18
- list += "<li><a href=\"#\" rel=\"gamefic\" data-command=\"#{o}\">#{o}</a></li>"
19
- }
20
- list += "</ol>"
21
- character.tell list
22
- end
23
- print Gamefic::Text::Html::Conversions.html_to_ansi(character.state[:output])
24
- end
25
-
26
- def save filename, snapshot
27
- File.open(filename, 'w') do |file|
28
- file << snapshot.to_json
29
- end
30
- end
31
-
32
- def restore filename
33
- json = File.read(filename)
34
- snapshot = JSON.parse(json, symbolize_names: true)
35
- engine.plot.restore snapshot
36
- end
37
- end
38
- end