Module: StoryTeller::Builtins

Includes:
Articles, Color, Plurals
Included in:
Inform::Object
Defined in:
lib/story_teller/builtins.rb

Overview

module Builtins

Constant Summary collapse

MethodDefinitionPattern =

rubocop: enable Metrics/AbcSize rubocop: enable Metrics/CyclomaticComplexity rubocop: enable Metrics/MethodLength rubocop: enable Metrics/PerceivedComplexity

/\s*def\s+/.freeze
MethodTerminationPattern =
/\s*end$/.freeze
VERB =
1
PLURAL =
4
PREPOSITION =
8
NOUN =
128

Constants included from Color

Color::BackgroundColorCodes, Color::ColorCodes, Color::NearestColor, Color::StyleCodes

Constants included from Articles

Articles::LowercaseASpaceString, Articles::LowercaseSomeSpaceString, Articles::LowercaseTheSpaceString

Instance Method Summary collapse

Methods included from Plurals

#apply_inflections, #plural?, #pluralize, #singular?, #singularize

Methods included from Color

#background_color, #color, #nearest_color, #style, #un_background_color, #un_color, #un_style

Methods included from Articles

#A, #Cthatorthose, #Ctheyreorthats, #The, #a, #cthatorthose, #ctheyreorthats, #defart, #indefart, #isorare, #itorthem, #thatorthose, #the

Instance Method Details

#__quitObject



288
289
290
291
# File 'lib/story_teller/builtins.rb', line 288

def __quit
  StoryTeller::Runtime.instance.quit_game
  publish :disconnect
end

#__readObject



284
285
286
# File 'lib/story_teller/builtins.rb', line 284

def __read
  StoryTeller::Runtime.instance.read
end

#__restart(*args) ⇒ Object



297
298
299
# File 'lib/story_teller/builtins.rb', line 297

def __restart(*args)
  StoryTeller::Runtime.instance.restart_game(*args)
end

#__restore(*args) ⇒ Object



305
306
307
# File 'lib/story_teller/builtins.rb', line 305

def __restore(*args)
  StoryTeller::Runtime.instance.restore_game(*args)
end

#__save(*args) ⇒ Object



301
302
303
# File 'lib/story_teller/builtins.rb', line 301

def __save(*args)
  StoryTeller::Runtime.instance.save_game(*args)
end

#__verify(*args) ⇒ Object



293
294
295
# File 'lib/story_teller/builtins.rb', line 293

def __verify(*args)
  StoryTeller::Runtime.instance.verify_game(*args)
end

#apply_instance_behavior!Object



109
110
111
112
113
114
115
116
# File 'lib/story_teller/builtins.rb', line 109

def apply_instance_behavior!
  source = self.properties[:instance_behavior]
  return if source.nil? || source.empty?
  return unless source.include?('def ')
  self.instance_eval(source, "(instance_behavior for #{self.identity})", 1)
rescue NameError => e
  log.warn "[InstanceBehavior] #{e.class}: #{e.message}"
end

#classificationObject



331
332
333
334
335
336
# File 'lib/story_teller/builtins.rb', line 331

def classification
  type = object_type.to_s
  clazz = self.class.to_s
  return type if type == clazz
  "#{type} < #{clazz}"
end

#compassObject



43
44
45
# File 'lib/story_teller/builtins.rb', line 43

def compass
  InformLibrary::Compass
end

#contentObject Also known as: contents



51
# File 'lib/story_teller/builtins.rb', line 51

def content; respond_to?(:descendants) ? self.descendants : Array::Empty; end

#current_wordObject



230
231
232
# File 'lib/story_teller/builtins.rb', line 230

def current_word
  @words[@wn] || ''
end

#deadflagObject



189
# File 'lib/story_teller/builtins.rb', line 189

def deadflag; @deadflag; end

#deadflag=(flag) ⇒ Object



191
# File 'lib/story_teller/builtins.rb', line 191

def deadflag=(flag); @deadflag = flag; end

#dict_par1(w, par = 0) ⇒ Object



355
356
357
358
359
360
361
362
# File 'lib/story_teller/builtins.rb', line 355

def dict_par1(w, par = 0)
  # +128 if given a noun, +8 if a preposition, +4 if plural, +1 if a verb
  par += NOUN if Inform::Dictionary.include?(w.to_sym)
  par += PREPOSITION if Inform::English::Prepositions.include?(w)
  par += PLURAL if plural?(w)
  par += VERB unless Inform::Grammar::Verbs.lookup(w).nil?
  par
end

#dictionaryObject



39
40
41
# File 'lib/story_teller/builtins.rb', line 39

def dictionary
  Inform::Dictionary
end

#disrobe(obj) ⇒ Object



280
281
282
# File 'lib/story_teller/builtins.rb', line 280

def disrobe(obj)
  invoke :Disrobe, obj
end

#drop(obj) ⇒ Object



272
273
274
# File 'lib/story_teller/builtins.rb', line 272

def drop(obj)
  invoke :Drop, obj
end

#emote(*s) ⇒ Object



267
268
269
270
# File 'lib/story_teller/builtins.rb', line 267

def emote(*s)
  return consult_words if s.empty?
  invoke :Emote, s.flatten.sample
end

#findobject(*args, &block) ⇒ Object



183
184
185
186
187
# File 'lib/story_teller/builtins.rb', line 183

def findobject(*args, &block)
  object_class = StoryTeller::ModelAdapter.object_class!
  return object_class.dataset.order(:name, :id).grep(:name, *args).to_a if args.first.is_a?(Regexp)
  object_class.dataset.grep(&block).to_a
end

#getobject(id) ⇒ Object



175
176
177
178
179
180
181
# File 'lib/story_teller/builtins.rb', line 175

def getobject(id)
  object_class = StoryTeller::ModelAdapter.object_class!
  o = object_class[id]
  o.refresh
rescue StandardError
  raise NoSuchObject
end

#go(obj) ⇒ Object



259
260
261
# File 'lib/story_teller/builtins.rb', line 259

def go(obj)
  invoke :Go, obj
end

#initialObject



122
123
124
# File 'lib/story_teller/builtins.rb', line 122

def initial
  # TODO: What is this supposed to return?
end

#language_descriptorsObject



245
246
247
248
249
250
# File 'lib/story_teller/builtins.rb', line 245

def language_descriptors
  # TODO: Cleanup upon disconnect
  key = self.respond_to?(:inflib) ? self.inflib : self.identity
  Inform::English::LanguageDescriptors[key] ||= Marshal.load(
    Marshal.dump(Inform::English::LanguageDescriptors[:default]))
end

#language_pronounsObject



238
239
240
241
242
243
# File 'lib/story_teller/builtins.rb', line 238

def language_pronouns
  # TODO: Cleanup upon disconnect
  key = self.respond_to?(:inflib) ? self.inflib : self.identity
  Inform::English::LanguagePronouns[key] ||= Marshal.load(
    Marshal.dump(Inform::English::LanguagePronouns[:default]))
end

#library_method?(method) ⇒ Boolean

Returns:

  • (Boolean)


347
348
349
# File 'lib/story_teller/builtins.rb', line 347

def library_method?(method)
  StoryTeller::Library.methods_index.include?(method) && respond_to?(method)
end

#life?(action_routine = action) ⇒ Boolean

Returns:

  • (Boolean)


157
158
159
160
161
162
163
164
# File 'lib/story_teller/builtins.rb', line 157

def life?(action_routine = action)
  return false if action_routine.nil?
  self.apply_modules if self.respond_to?(:apply_modules)
  self.provides?('life_' + action_routine)
rescue StandardError => e
  log.error "Error checking for life reaction: #{e.message}", e
  false
end

#light_adjusted(obj = @player) ⇒ Object



252
253
254
255
256
257
# File 'lib/story_teller/builtins.rb', line 252

def light_adjusted(obj = @player)
  # TODO: Consider performing the following in another thread or an event
  obj.root.descendants.each do |o|
    o.inflib.send(:AdjustLight, true) if o.has?(:creature) && !o.inflib.nil?
  end
end

#method_source(method_name) ⇒ Object



103
104
105
106
107
# File 'lib/story_teller/builtins.rb', line 103

def method_source(method_name)
  self.singleton_class.instance_method(method_name).source
rescue StandardError => _e
  nil
end

#nothingObject



47
48
49
# File 'lib/story_teller/builtins.rb', line 47

def nothing
  nil
end

#num_wordsObject



226
227
228
# File 'lib/story_teller/builtins.rb', line 226

def num_words
  @words.nil? || @words.empty? ? 0 : @words.length
end

#number(x = nil) ⇒ Object



216
217
218
219
220
# File 'lib/story_teller/builtins.rb', line 216

def number(x = nil)
  return special_number1 if x.nil?
  LanguageNumber(x)
  ''
end

#objectloop(*_args, &block) ⇒ Object



166
167
168
169
170
171
172
173
# File 'lib/story_teller/builtins.rb', line 166

def objectloop(*_args, &block)
  if self.is_a?(InformLibrary)
    object_class = StoryTeller::ModelAdapter.object_class
    object_class&.all&.each { |o| block.call(o) }
  elsif self.respond_to?(:descendants)
    self.descendants.each { |o| block.call(o) }
  end
end

#ofclass(klass) ⇒ Object Also known as: ofclass?



126
127
128
# File 'lib/story_teller/builtins.rb', line 126

def ofclass(klass)
  self.is_a?(klass)
end

#pause(n) ⇒ Object



342
343
344
345
# File 'lib/story_teller/builtins.rb', line 342

def pause(n)
  sleep(n)
  :inform
end

#provides?(prop) ⇒ Boolean

Returns:

  • (Boolean)


131
132
133
134
135
136
137
# File 'lib/story_teller/builtins.rb', line 131

def provides?(prop)
  symbolized_prop = prop.to_sym
  return symbolized_prop if self.respond_to?(symbolized_prop)
  downcased_prop = symbolized_prop.downcase
  return downcased_prop if self.respond_to?(downcased_prop)
  false
end

#randomly(n = 3) ⇒ Object



338
339
340
# File 'lib/story_teller/builtins.rb', line 338

def randomly(n = 3)
  rand * n
end

#react_after?(action_routine = action) ⇒ Boolean

Returns:

  • (Boolean)


139
140
141
142
143
144
145
146
# File 'lib/story_teller/builtins.rb', line 139

def react_after?(action_routine = action)
  return false if action_routine.nil?
  self.apply_modules if self.respond_to?(:apply_modules)
  self.provides?('react_after_' + action_routine)
rescue StandardError => e
  log.error "Error checking for after reaction: #{e.message}", e
  false
end

#react_before?(action_routine = action) ⇒ Boolean

Returns:

  • (Boolean)


148
149
150
151
152
153
154
155
# File 'lib/story_teller/builtins.rb', line 148

def react_before?(action_routine = action)
  return false if action_routine.nil?
  self.apply_modules if self.respond_to?(:apply_modules)
  self.provides?('react_before_' + action_routine)
rescue StandardError => e
  log.error "Error checking for before reaction: #{e.message}", e
  false
end

#remaining_wordsObject



234
235
236
# File 'lib/story_teller/builtins.rb', line 234

def remaining_words
  @words[@wn..]
end

#resembles_method?(source) ⇒ Boolean

Returns:

  • (Boolean)


99
100
101
# File 'lib/story_teller/builtins.rb', line 99

def resembles_method?(source)
  MethodDefinitionPattern.match?(source) && MethodTerminationPattern.match?(source)
end

#say(*s) ⇒ Object



263
264
265
# File 'lib/story_teller/builtins.rb', line 263

def say(*s)
  invoke :Say, s.flatten.sample
end

#scoreObject



197
# File 'lib/story_teller/builtins.rb', line 197

def score; @score.nil? ? 0 : @score; end

#score=(score) ⇒ Object



199
# File 'lib/story_teller/builtins.rb', line 199

def score=(score); @score = score; end

#search(obj) ⇒ Object



276
277
278
# File 'lib/story_teller/builtins.rb', line 276

def search(obj)
  invoke :Search, obj
end

#specialObject



222
223
224
# File 'lib/story_teller/builtins.rb', line 222

def special
  @special_word
end

#the_timeObject



193
# File 'lib/story_teller/builtins.rb', line 193

def the_time; @the_time.nil? ? 0 : @the_time; end

#the_time=(the_time) ⇒ Object



195
# File 'lib/story_teller/builtins.rb', line 195

def the_time=(the_time); @the_time = the_time; end

#things_scoreObject



201
# File 'lib/story_teller/builtins.rb', line 201

def things_score; @things_score.nil? ? 0 : @things_score; end

#things_score=(things_score) ⇒ Object



203
# File 'lib/story_teller/builtins.rb', line 203

def things_score=(things_score); @things_score = things_score; end

#to_sObject Also known as: to_str


(From the Inform Designer's Manual)
§26 Describing objects and rooms

To print the name of such an object, Inform does the following:

(1) If the short_name is a string, it's printed and that's all.
(2) If it is a routine, then it is called. If it returns true, that's all.
(3) The text given in the header of the object definition is printed.



319
320
321
322
323
324
325
326
327
328
# File 'lib/story_teller/builtins.rb', line 319

def to_s
  textual_name = self.short_name if self.respond_to?(:short_name)
  return textual_name if textual_name.is_a?(String)  # (1)
  return if textual_name == true                     # (2)
  if self.respond_to?(:name)
    return self.name.join(' ') if self.name.respond_to?(:join)
    return self.name.to_s                            # (3)
  end
  self.identity
end

#topicObject Also known as: text



211
212
213
# File 'lib/story_teller/builtins.rb', line 211

def topic
  consult_words
end

#visibility_ceiling=(visibility_ceiling) ⇒ Object



205
206
207
208
209
# File 'lib/story_teller/builtins.rb', line 205

def visibility_ceiling=(visibility_ceiling)
  e = Thread.current[:event]
  @visibility_ceiling = visibility_ceiling
  e.visibility_ceiling = visibility_ceiling if e
end

#with(context = nil, &block) ⇒ Object

rubocop: disable Metrics/AbcSize rubocop: disable Metrics/CyclomaticComplexity rubocop: disable Metrics/MethodLength rubocop: disable Metrics/PerceivedComplexity



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/story_teller/builtins.rb', line 58

def with(context = nil, &block)
  return self if block.nil?
  existing_methods = self.singleton_methods(false)

  if context.nil?
    self.instance_eval(&block)
  else
    self.instance_exec(context, &block)
  end

  # Only persist methods being defined just now on *this* instance
  added = self.singleton_methods(false) - existing_methods
  added.select! do |m|
    self.singleton_class.instance_method(m).owner == self.singleton_class
  end

  if added.any?
    persisted = self.properties.fetch(:instance_behavior, '')
    added.each do |method_name|
      source = method_source(method_name)
      next if source.nil?
      # Only support def ... end blocks
      next unless resembles_method?(source)
      persisted << source unless persisted.include?(source)
    end
    unless persisted.empty?
      self.will_change_column(:properties) if self.respond_to?(:will_change_column)
      self.properties[:instance_behavior] = persisted
    end
  end
  self.save_changes if self.respond_to?(:save_changes)
  self
end

#workflagsObject



118
119
120
# File 'lib/story_teller/builtins.rb', line 118

def workflags
  Thread.current[:workflags] ||= Set.new
end