gamefic 1.3.2 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/gamefic/html.rb CHANGED
@@ -1,20 +1,20 @@
1
1
  require 'rexml/document'
2
2
 
3
- module Gamefic
4
-
3
+ module Gamefic
4
+
5
5
  module Html
6
6
  # Convert ampersands to &
7
7
  #
8
8
  # @param text [String]
9
- # @return [String]
10
- def self.fix_ampersands(text)
11
- codes = []
12
- ENTITIES.keys.each { |e|
13
- codes.push e[1..-1]
14
- }
15
- piped = codes.join('|')
16
- re = Regexp.new("&(?!(#{piped}))")
17
- text.gsub(re, '&\1')
9
+ # @return [String]
10
+ def self.fix_ampersands(text)
11
+ codes = []
12
+ ENTITIES.keys.each { |e|
13
+ codes.push e[1..-1]
14
+ }
15
+ piped = codes.join('|')
16
+ re = Regexp.new("&(?!(#{piped}))")
17
+ text.gsub(re, '&\1')
18
18
  end
19
19
 
20
20
  # Encode a String with HTML entities
@@ -22,10 +22,11 @@ module Gamefic
22
22
  # @param text [String]
23
23
  # @return [String]
24
24
  def self.encode(text)
25
+ encoded = text
25
26
  Gamefic::Html::ENTITIES.each { |k, v|
26
- text = text.gsub(v, k)
27
+ encoded = encoded.gsub(v, k)
27
28
  }
28
- text
29
+ encoded
29
30
  end
30
31
 
31
32
  # Decode a String's HTML entities
@@ -58,10 +59,10 @@ module Gamefic
58
59
  raise e
59
60
  end
60
61
  end
61
- end
62
-
63
- module Html
64
- 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;" => "♦" }
65
62
  end
66
-
67
- end
63
+
64
+ module Html
65
+ 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;" => "♦" }
66
+ end
67
+
68
+ end
@@ -0,0 +1,185 @@
1
+ require 'gamefic/ansi'
2
+ require 'gamefic/html'
3
+ require 'io/console'
4
+
5
+ module Gamefic
6
+
7
+ module HtmlToAnsi
8
+ include Ansi
9
+ include Ansi::Code
10
+
11
+ def html_to_ansi text, wrap: true, width: nil
12
+ return '' if text.strip == ''
13
+ output = ''
14
+ begin
15
+ doc = Html.parse("<body>#{text.strip}</body>")
16
+ format_recursively doc
17
+ texts = REXML::XPath.match(doc, './/text()')
18
+ output = texts.join('').gsub(/&apos;/, "'").gsub(/&quot;/, '"').gsub(/&lt;/, '<').gsub(/&gt;/, '>')
19
+ output += Ansi.graphics_mode(Attribute::NORMAL)
20
+ output = Html.decode(output)
21
+ rescue REXML::ParseException => e
22
+ output = Html.encode(text) + "\n\n"
23
+ #output = data
24
+ end
25
+ output.gsub!(/(\n\n)+/, "\n\n")
26
+ calc_width = size[0] || width
27
+ if calc_width.nil? or !wrap
28
+ output
29
+ else
30
+ terminalize(output, calc_width - 1)
31
+ end
32
+ output
33
+ end
34
+
35
+ private
36
+
37
+ def format_recursively(top, stack = nil)
38
+ ol_index = 1
39
+ stack ||= [Attribute::NORMAL]
40
+ top.elements.each { |element|
41
+ formats = [Attribute::NORMAL]
42
+ classes = element.attribute('class').to_s.split(' ')
43
+ if classes.include?('hint')
44
+ formats.push Foreground::YELLOW
45
+ end
46
+ case element.name
47
+ when 'strong', 'b'
48
+ formats.push Attribute::BOLD
49
+ when 'em', 'i', 'u'
50
+ formats.push Attribute::UNDERSCORE
51
+ when 'a'
52
+ if element.attributes['rel'].to_s == 'gamefic'
53
+ element.attributes['href'] = element.attributes['href'][5..-1]
54
+ formats.push [Attribute::UNDERSCORE, Extra::COMMAND]
55
+ else
56
+ formats.push [Attribute::UNDERSCORE, Extra::HREF]
57
+ end
58
+ when 'li'
59
+ if top.name == 'ol'
60
+ element.text = "#{ol_index}. #{element.text}"
61
+ ol_index += 1
62
+ else
63
+ element.text = "* #{element.text}"
64
+ end
65
+ formats.push [Extra::LINE]
66
+ when 'img'
67
+ formats.push [Extra::IGNORED]
68
+ when 'body', 'p', 'ol', 'ul'
69
+ formats.push Extra::BLOCK
70
+ when 'pre'
71
+ formats.push [Extra::BLOCK, Extra::PRE]
72
+ when 'nav'
73
+ formats.push Extra::BLOCK
74
+ when 'h1', 'h2', 'h3', 'h4', 'h5'
75
+ formats.push [Attribute::BOLD, Extra::BLOCK, Extra::UPPERCASE]
76
+ when 'kbd'
77
+ formats.push [Foreground::GREEN]
78
+ end
79
+ if has_code?(stack, Extra::IGNORED)
80
+ element.parent.delete_element(element)
81
+ end
82
+ stack.push formats
83
+ if has_code?(stack, Extra::UPPERCASE)
84
+ element.texts.each { |text|
85
+ text.value.upcase!
86
+ }
87
+ end
88
+ element.texts.each { |text|
89
+ text.value = "#{Ansi.graphics_mode(*stack)}#{text.value}"
90
+ }
91
+ if has_code?(stack.last, Extra::IMAGE)
92
+ element.text = "#{element.attribute('alt') ? element.attribute('alt') : '[Image]'}"
93
+ end
94
+ format_recursively element, stack
95
+ if has_code?(stack.last, Extra::COMMAND)
96
+ if element.attribute('data-command').to_s != ''
97
+ tmp = stack.pop
98
+ element.add_text "#{Ansi.graphics_mode(*stack)}"
99
+ element.add_text " [#{element.attribute('data-command')}]"
100
+ stack.push tmp
101
+ element.add_text "#{Ansi.graphics_mode(*stack)}"
102
+ end
103
+ end
104
+ if has_code?(stack.last, Extra::BLOCK) and !has_code?(stack.last, Extra::PRE)
105
+ element.texts.first.value.lstrip! unless element.texts.first.nil?
106
+ element.texts.last.value.rstrip! unless element.texts.last.nil?
107
+ element.texts.each { |t|
108
+ t.value = t.value.gsub(/ +/, ' ').strip
109
+ }
110
+ end
111
+ if has_code?(stack.last, Extra::BLOCK)
112
+ element.add_text("\n\n")
113
+ elsif has_code?(stack.last, Extra::LINE)
114
+ if !has_code?(stack[-2], Extra::BLOCK) || element != top.elements.to_a.last
115
+ element.add_text("\n")
116
+ end
117
+ end
118
+ if has_code?(stack.last, Extra::HREF)
119
+ if element.attribute('href').to_s != "#"
120
+ tmp = stack.pop
121
+ element.add_text "#{Ansi.graphics_mode(*stack)}"
122
+ element.add_text(" [#{element.attribute('href')}]")
123
+ stack.push tmp
124
+ element.add_text "#{Ansi.graphics_mode(*stack)}"
125
+ end
126
+ end
127
+ if has_code?(stack.last, Extra::IMAGE)
128
+ element.add_text(" [#{element.attribute('src')}]")
129
+ if !has_code?(stack, Extra::BLOCK)
130
+ element.add_text("\n\n")
131
+ end
132
+ end
133
+ stack.pop
134
+ }
135
+ end
136
+
137
+ def terminalize string, max_length
138
+ i = 0
139
+ output = ''
140
+ line_length = 0
141
+ while i < string.length
142
+ line_length += 1
143
+ char = string[i,1]
144
+ if char == "\e"
145
+ # Right now, graphics modes are the only supported ANSI sequences.
146
+ end_of_seq = string.index("m", i)
147
+ output += string[i..end_of_seq]
148
+ i = end_of_seq + 1
149
+ elsif char == " "
150
+ next_space = string.index(/[\s]/, i + 1)
151
+ if !next_space.nil? and line_length + (next_space - i) > max_length
152
+ output += "\n"
153
+ line_length = 0
154
+ else
155
+ output += char
156
+ end
157
+ i += 1
158
+ else
159
+ if char == "\n"
160
+ line_length = 0
161
+ end
162
+ output += char
163
+ i += 1
164
+ end
165
+ end
166
+ output #output.strip
167
+ end
168
+
169
+ def has_code?(fmt, code)
170
+ if fmt.kind_of?(Array)
171
+ return fmt.flatten.include?(code)
172
+ end
173
+ return fmt == code
174
+ end
175
+
176
+ def size
177
+ begin
178
+ return STDOUT.winsize.reverse
179
+ rescue
180
+ return [nil,nil]
181
+ end
182
+ end
183
+ end
184
+
185
+ end
data/lib/gamefic/plot.rb CHANGED
@@ -67,7 +67,7 @@ module Gamefic
67
67
 
68
68
  # Get an Array of all Actions defined in the Plot.
69
69
  #
70
- # @return Array[Action]
70
+ # @return [Array<Action>]
71
71
  def actions
72
72
  @commands.values.flatten
73
73
  end
@@ -75,7 +75,7 @@ module Gamefic
75
75
  # Get an Array of all Actions associated with the specified verb.
76
76
  #
77
77
  # @param verb [Symbol] The Symbol for the verb (e.g., :go or :look)
78
- # @return Array<Action> The verb's associated Actions
78
+ # @return [Array<Action>] The verb's associated Actions
79
79
  def actions_with_verb(verb)
80
80
  @commands[verb].clone || []
81
81
  end
@@ -202,30 +202,20 @@ module Gamefic
202
202
  # Update the Plot's current turn of gameplay.
203
203
  # This method is typically called by the Engine that manages game execution.
204
204
  def update
205
- # Update the plot.
206
205
  @players.each { |player|
207
- # TODO: This really doesn't belong here. We need a before_update in the plot.
208
- @before_player_update_procs.each { |p|
209
- p.call player
210
- }
211
- this_scene = player.next_scene || player.scene
212
- player.prepare nil
213
- if this_scene != player.scene
214
- player.cue this_scene
215
- player.queue.shift
216
- else
206
+ @before_player_update_procs.each { |p| p.call player }
207
+ this_scene = player.next_scene || player.scene
208
+ player.prepare nil
209
+ if this_scene != player.scene
210
+ player.cue this_scene
211
+ player.queue.shift
212
+ else
217
213
  process_input player
218
214
  end
219
215
  }
220
- @entities.each { |e|
221
- e.update
222
- }
223
- @players.each { |player|
224
- update_player player
225
- }
226
- @update_procs.each { |p|
227
- p.call
228
- }
216
+ @entities.each { |e| e.update }
217
+ @players.each { |player| update_player player }
218
+ @update_procs.each { |p| p.call }
229
219
  end
230
220
 
231
221
  def tell entities, message, refresh = false
@@ -294,13 +284,14 @@ module Gamefic
294
284
  end
295
285
  def rem_entity(entity)
296
286
  @entities.delete(entity)
287
+ @players.delete(entity)
297
288
  end
298
289
  def recursive_update(entity)
299
290
  entity.update
300
291
  entity.children.each { |e|
301
292
  recursive_update e
302
293
  }
303
- end
294
+ end
304
295
  def add_syntax syntax
305
296
  if @commands[syntax.verb] == nil
306
297
  raise "Action \"#{syntax.verb}\" does not exist."
@@ -317,12 +308,10 @@ module Gamefic
317
308
  else
318
309
  b.token_count <=> a.token_count
319
310
  end
320
- }
311
+ }
321
312
  end
322
313
  def add_action(action)
323
- if (@commands[action.verb] == nil)
324
- @commands[action.verb] = Array.new
325
- end
314
+ @commands[action.verb] ||= []
326
315
  @commands[action.verb].unshift action
327
316
  @commands[action.verb].sort! { |a, b|
328
317
  if a.specificity == b.specificity
@@ -333,9 +322,12 @@ module Gamefic
333
322
  b.specificity <=> a.specificity
334
323
  end
335
324
  }
325
+ generate_default_syntax action
326
+ end
327
+ def generate_default_syntax action
336
328
  user_friendly = action.verb.to_s.gsub(/_/, ' ')
337
- args = Array.new
338
- used_names = Array.new
329
+ args = []
330
+ used_names = []
339
331
  action.queries.each { |c|
340
332
  num = 1
341
333
  new_name = ":var"
@@ -5,15 +5,19 @@ module Gamefic
5
5
 
6
6
  module Plot::SceneMount
7
7
  # Create a multiple-choice scene.
8
- # The user will be required to make a valid choice to continue
8
+ # The user will be required to make a valid choice to continue.
9
9
  #
10
10
  # @yieldparam [Character]
11
- # @yieldparam [String]
12
- def multiple_choice key, options, &block
13
- scenes[key] = Scene::MultipleChoice.new(
14
- options: options,
15
- finish: block
16
- )
11
+ # @yieldparam [Scene::Data::MultipleChoice]
12
+ def multiple_choice key, *choices, &block
13
+ scenes[key] = Scene::MultipleChoice.new
14
+ scenes[key].on_start do |actor, data|
15
+ data.options.push *choices
16
+ end
17
+ scenes[key].on_finish do |actor, data|
18
+ block.call actor, data unless block.nil?
19
+ actor.cue :active if actor.scene == key and actor.next_scene.nil?
20
+ end
17
21
  end
18
22
 
19
23
  # Create a yes-or-no scene.
@@ -22,50 +26,113 @@ module Gamefic
22
26
  # @yieldparam [Character]
23
27
  # @yieldparam [String] "yes" or "no"
24
28
  def yes_or_no key, prompt = nil, &block
25
- scenes[key] = Scene::YesOrNo.new(prompt, &block)
29
+ scenes[key] = Scene::YesOrNo.new
30
+ unless prompt.nil?
31
+ scenes[key].on_start do |actor, data|
32
+ data.prompt = prompt
33
+ end
34
+ end
35
+ scenes[key].on_finish &block
26
36
  end
27
37
 
28
- # Create a scene with a prompt.
29
- # This scene will use the provided block to process arbitrary input
30
- # from the user.
31
- #
32
- # @param key [Symbol] A unique name for the scene.
33
- # @param prompt [String] The input prompt to display to the user.
34
- # @yieldparam [Character]
35
- # @yieldparam [String]
36
- def question key, prompt, &block
37
- scenes[key] = Scene::Question.new prompt, &block
38
+ def question key, prompt = 'What is your answer?', &block
39
+ scenes[key] = Scene::Custom.new
40
+ scenes[key].on_start do |actor, data|
41
+ data.prompt = prompt
42
+ end
43
+ scenes[key].on_finish do |actor, data|
44
+ block.call actor, data unless block.nil?
45
+ actor.cue :active if actor.scene == key and actor.next_scene.nil?
46
+ end
38
47
  end
39
-
48
+
40
49
  # Create a scene that pauses the game.
41
- # This scene will execute the specified block and wait for input
42
- # from the user (e.g., pressing Enter) to continue.
50
+ # This scene will execute the specified block and wait for input from the
51
+ # the user (e.g., pressing Enter) to continue.
43
52
  #
44
53
  # @param key [Symbol] A unique name for the scene.
54
+ # @param prompt [String] The text to display when prompting the user to continue.
45
55
  # @yieldparam [Character]
46
- def pause key, &block
47
- scenes[key] = Scene::Pause.new &block
56
+ # @yieldparam [Scene::Data::Base]
57
+ def pause key, prompt = nil, &block
58
+ scenes[key] = Scene::Pause.new
59
+ scenes[key].on_start do |actor, data|
60
+ data.prompt = prompt unless prompt.nil?
61
+ block.call actor, data unless block.nil?
62
+ end
63
+ scenes[key].on_finish do |actor, data|
64
+ actor.cue :active if actor.scene == key and actor.next_scene.nil?
65
+ end
48
66
  end
49
67
 
50
68
  # Create a conclusion.
51
- # The game will end after this scene is complete.
69
+ # The game (or the character's participation in it) will end after this
70
+ # scene is complete.
52
71
  #
53
72
  # @param key [Symbol] A unique name for the scene.
54
73
  # @yieldparam [Character]
74
+ # @yieldparam [Scene::Data::Base]
55
75
  def conclusion key, &block
56
- scenes[key] = Scene::Conclusion.new &block
76
+ scenes[key] = Scene::Conclusion.new
77
+ scenes[key].on_start &block
57
78
  end
58
79
 
59
- # Create a generic scene.
60
- # After the scene is complete, it will automatically start the next
61
- # prepared scene, or the :active scene if none is prepared.
80
+ # Create a passive scene.
81
+ # Passive scenes will cue the active scene if another scene
82
+ # has not been prepared or cued.
62
83
  #
63
84
  # @param [Symbol] A unique name for the scene.
64
85
  # @yieldparam [Character]
65
- def scene key, &block
66
- scenes[key] = Scene::Passive.new &block
86
+ # @yieldparam [Scene::Data::Base]
87
+ def passive key, &block
88
+ scenes[key] = Scene::Custom.new
89
+ scenes[key].on_start do |actor, data|
90
+ block.call actor, data
91
+ actor.cue :active if actor.scene == key and actor.next_scene.nil?
92
+ end
67
93
  end
68
-
94
+
95
+ # Create a custom scene.
96
+ #
97
+ # Custom scenes should always specify the next scene to be cued or
98
+ # prepared. If not, the scene will get repeated on the next turn.
99
+ #
100
+ # This method creates a Scene::Custom by default. You can customize other
101
+ # scene types by specifying the class to create.
102
+ #
103
+ # @example Ask the user for a name
104
+ # scene :ask_for_name do |scene|
105
+ # scene.on_start do |actor, data|
106
+ # data.prompt = "What's your name?"
107
+ # end
108
+ # scene.on_finish do |actor, data|
109
+ # actor.name = data.input
110
+ # actor.tell "Hello, #{actor.name}!"
111
+ # actor.cue :active
112
+ # end
113
+ # end
114
+ #
115
+ # @example Customize the prompt for a MultipleChoice scene
116
+ # scene :ask_for_choice, Scene::MultipleChoice do |scene|
117
+ # scene.on_start do |actor, data|
118
+ # data.options.push 'red', 'green', 'blue'
119
+ # data.prompt = "Which color?"
120
+ # end
121
+ # scene.on_finish do |actor, data|
122
+ # actor.tell "You chose #{data.selection}"
123
+ # actor.cue :active
124
+ # end
125
+ # end
126
+ #
127
+ # @param key [Symbol] A unique name for the scene.
128
+ # @param key [cls] The class of scene to be instantiated.
129
+ # @yieldparam [Scene::Custom] The instantiated scene.
130
+ def scene key, cls = Scene::Custom, &block
131
+ scenes[key] = cls.new
132
+ #block.call scenes[key]
133
+ yield scenes[key] if block_given?
134
+ end
135
+
69
136
  # Choose a new scene based on a list of options.
70
137
  # This is a specialized type of multiple-choice scene that determines
71
138
  # which scene to cue based on a Hash of choices and scene keys.
@@ -85,12 +152,12 @@ module Gamefic
85
152
  # @param key [Symbol] A unique name for the scene.
86
153
  # @param map [Hash] A Hash of options and associated scene keys.
87
154
  def multiple_scene key, map
88
- scenes[key] = Scene::MultipleChoice.new(
89
- options: map.keys,
90
- finish: proc { |actor, input|
91
- actor.cue map[input.choice]
155
+ scenes[key] = Scene::MultipleChoice.new
156
+ scenes[key].on_start do |actor, data|
157
+ map.each { |k, v|
158
+ data.map k, v
92
159
  }
93
- )
160
+ end
94
161
  end
95
162
 
96
163
  end