Module: StoryTeller::Builtins

Includes:
Articles, Color, Plurals
Included in:
Inform, Inform::Ephemeral::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



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

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

#__readObject



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

def __read
  StoryTeller::Runtime.instance.read
end

#__restart(*args) ⇒ Object



350
351
352
# File 'lib/story_teller/builtins.rb', line 350

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

#__restore(*args) ⇒ Object



358
359
360
# File 'lib/story_teller/builtins.rb', line 358

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

#__save(*args) ⇒ Object



354
355
356
# File 'lib/story_teller/builtins.rb', line 354

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

#__verify(*args) ⇒ Object



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

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



384
385
386
387
388
389
# File 'lib/story_teller/builtins.rb', line 384

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



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

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

#deadflagObject



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

def deadflag; @deadflag; end

#deadflag=(flag) ⇒ Object



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

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

#dict_par1(w, par = 0) ⇒ Object



408
409
410
411
412
413
414
415
# File 'lib/story_teller/builtins.rb', line 408

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



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

def disrobe(obj)
  invoke :Disrobe, obj
end

#drop(obj) ⇒ Object



325
326
327
# File 'lib/story_teller/builtins.rb', line 325

def drop(obj)
  invoke :Drop, obj
end

#emote(*s) ⇒ Object



320
321
322
323
# File 'lib/story_teller/builtins.rb', line 320

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

#findobject(*args, &block) ⇒ Object

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



185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
# File 'lib/story_teller/builtins.rb', line 185

def findobject(*args, &block)
  object_class = inform_object_class

  if sequel_model?(object_class)
    return object_class.dataset.order(:name, :id).grep(:name, *args).to_a if args.first.is_a?(Regexp)

    return object_class.dataset.grep(&block).to_a
  end

  objects = inform_object_collection
  if args.first.is_a?(Regexp)
    return objects.select do |object|
      object_name_matches?(object, args.first)
    end
  end

  block.nil? ? objects : objects.select(&block)
end

#getobject(id) ⇒ Object



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

def getobject(id)
  object = inform_object_fetch(id)
  object.refresh if object.respond_to?(:refresh)
  object
rescue StandardError
  raise NoSuchObject
end

#go(obj) ⇒ Object



312
313
314
# File 'lib/story_teller/builtins.rb', line 312

def go(obj)
  invoke :Go, obj
end

#inform_object_classObject

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



207
208
209
210
211
212
213
# File 'lib/story_teller/builtins.rb', line 207

def inform_object_class
  if defined?(Inform::Object) && sequel_model?(Inform::Object)
    Inform::Object
  elsif defined?(Inform::Ephemeral::Object)
    Inform::Ephemeral::Object
  end
end

#inform_object_collectionObject



219
220
221
222
223
224
225
# File 'lib/story_teller/builtins.rb', line 219

def inform_object_collection
  object_class = inform_object_class
  return Array::Empty if object_class.nil?
  return object_class.all if object_class.respond_to?(:all)

  Array::Empty
end

#inform_object_fetch(id) ⇒ Object

Raises:

  • (NoSuchObject)


227
228
229
230
231
232
233
234
235
# File 'lib/story_teller/builtins.rb', line 227

def inform_object_fetch(id)
  object_class = inform_object_class
  raise NoSuchObject if object_class.nil?

  object = object_class[id] if object_class.respond_to?(:[])
  raise NoSuchObject if object.nil?

  object
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



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

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



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

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)


400
401
402
# File 'lib/story_teller/builtins.rb', line 400

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



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

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



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

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

#number(x = nil) ⇒ Object



269
270
271
272
273
# File 'lib/story_teller/builtins.rb', line 269

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

#object_name_matches?(object, pattern) ⇒ Boolean

Returns:

  • (Boolean)


237
238
239
240
# File 'lib/story_teller/builtins.rb', line 237

def object_name_matches?(object, pattern)
  name = object.name if object.respond_to?(:name)
  Array(name).any? { |part| part.to_s.match?(pattern) } || name.to_s.match?(pattern)
end

#objectloop(*_args, &block) ⇒ Object



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

def objectloop(*_args, &block)
  if self.is_a?(InformLibrary)
    inform_object_collection.each { |object| block.call(object) }
  elsif self.respond_to?(:descendants)
    self.descendants.each { |object| block.call(object) }
  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



395
396
397
398
# File 'lib/story_teller/builtins.rb', line 395

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



391
392
393
# File 'lib/story_teller/builtins.rb', line 391

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



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

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



316
317
318
# File 'lib/story_teller/builtins.rb', line 316

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

#scoreObject



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

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

#score=(score) ⇒ Object



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

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

#search(obj) ⇒ Object



329
330
331
# File 'lib/story_teller/builtins.rb', line 329

def search(obj)
  invoke :Search, obj
end

#sequel_model?(object_class) ⇒ Boolean

Returns:

  • (Boolean)


215
216
217
# File 'lib/story_teller/builtins.rb', line 215

def sequel_model?(object_class)
  !object_class.nil? && object_class.respond_to?(:dataset)
end

#specialObject



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

def special
  @special_word
end

#the_timeObject



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

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

#the_time=(the_time) ⇒ Object



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

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

#things_scoreObject



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

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

#things_score=(things_score) ⇒ Object



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

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.



372
373
374
375
376
377
378
379
380
381
# File 'lib/story_teller/builtins.rb', line 372

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



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

def topic
  consult_words
end

#visibility_ceiling=(visibility_ceiling) ⇒ Object



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

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