inform-runtime 1.0.4
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.
- checksums.yaml +7 -0
- data/LICENSE +623 -0
- data/README.md +185 -0
- data/Rakefile +65 -0
- data/config/database.yml +37 -0
- data/exe/inform.rb +6 -0
- data/game/config.yml +5 -0
- data/game/example.inf +76 -0
- data/game/example.rb +90 -0
- data/game/forms/example_form.rb +2 -0
- data/game/grammar/game_grammar.inf.rb +11 -0
- data/game/languages/english.rb +2 -0
- data/game/models/example_model.rb +2 -0
- data/game/modules/example_module.rb +9 -0
- data/game/rules/example_state.rb +2 -0
- data/game/scripts/example_script.rb +2 -0
- data/game/topics/example_topic.rb +2 -0
- data/game/verbs/game_verbs.rb +15 -0
- data/game/verbs/metaverbs.rb +2028 -0
- data/lib/runtime/articles.rb +138 -0
- data/lib/runtime/builtins.rb +359 -0
- data/lib/runtime/color.rb +145 -0
- data/lib/runtime/command.rb +470 -0
- data/lib/runtime/config.rb +48 -0
- data/lib/runtime/context.rb +78 -0
- data/lib/runtime/daemon.rb +266 -0
- data/lib/runtime/database.rb +500 -0
- data/lib/runtime/events.rb +771 -0
- data/lib/runtime/experimental/handler_dsl.rb +175 -0
- data/lib/runtime/game.rb +74 -0
- data/lib/runtime/game_loader.rb +132 -0
- data/lib/runtime/grammar_parser.rb +553 -0
- data/lib/runtime/helpers.rb +177 -0
- data/lib/runtime/history.rb +45 -0
- data/lib/runtime/inflector.rb +195 -0
- data/lib/runtime/io.rb +174 -0
- data/lib/runtime/kernel.rb +450 -0
- data/lib/runtime/library.rb +59 -0
- data/lib/runtime/library_loader.rb +135 -0
- data/lib/runtime/link.rb +158 -0
- data/lib/runtime/logging.rb +197 -0
- data/lib/runtime/mixins.rb +570 -0
- data/lib/runtime/module.rb +202 -0
- data/lib/runtime/object.rb +761 -0
- data/lib/runtime/options.rb +104 -0
- data/lib/runtime/persistence.rb +292 -0
- data/lib/runtime/plurals.rb +60 -0
- data/lib/runtime/prototype.rb +307 -0
- data/lib/runtime/publication.rb +92 -0
- data/lib/runtime/runtime.rb +321 -0
- data/lib/runtime/session.rb +202 -0
- data/lib/runtime/stdlib.rb +604 -0
- data/lib/runtime/subscription.rb +47 -0
- data/lib/runtime/tag.rb +287 -0
- data/lib/runtime/tree.rb +204 -0
- data/lib/runtime/version.rb +24 -0
- data/lib/runtime/world_tree.rb +69 -0
- data/lib/runtime.rb +35 -0
- metadata +199 -0
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
# frozen_string_literal: false
|
|
3
|
+
|
|
4
|
+
# Copyright Nels Nelson 2008-2023 but freely usable (see license)
|
|
5
|
+
#
|
|
6
|
+
# This file is part of the Inform Runtime.
|
|
7
|
+
#
|
|
8
|
+
# The Inform Runtime is free software: you can redistribute it and/or
|
|
9
|
+
# modify it under the terms of the GNU General Public License as published
|
|
10
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
|
11
|
+
# (at your option) any later version.
|
|
12
|
+
#
|
|
13
|
+
# The Inform Runtime is distributed in the hope that it will be useful,
|
|
14
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
15
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
16
|
+
# GNU General Public License for more details.
|
|
17
|
+
#
|
|
18
|
+
# You should have received a copy of the GNU General Public License
|
|
19
|
+
# along with the Inform Runtime. If not, see <http://www.gnu.org/licenses/>.
|
|
20
|
+
|
|
21
|
+
# The Inform module
|
|
22
|
+
module Inform
|
|
23
|
+
# The Articles module
|
|
24
|
+
# Support standard Inform methods for dynamically applying appropriate
|
|
25
|
+
# articles to nouns.
|
|
26
|
+
module Articles
|
|
27
|
+
LowercaseTheSpaceString = 'the '.freeze
|
|
28
|
+
LowercaseSomeSpaceString = 'some '.freeze
|
|
29
|
+
|
|
30
|
+
# TODO: Add support for on-the-fly indefinite/definite mode
|
|
31
|
+
# differentiation based on the inclusion of the noun (x1) in
|
|
32
|
+
# the pronouns table.
|
|
33
|
+
# rubocop: disable Metrics/AbcSize
|
|
34
|
+
# rubocop: disable Metrics/CyclomaticComplexity
|
|
35
|
+
def the(obj)
|
|
36
|
+
return Inform::English::NOTHING__TX if obj.nil?
|
|
37
|
+
return PrefaceByArticle(obj, 0) if obj.is_a?(String)
|
|
38
|
+
return obj.to_s unless obj.respond_to?(:has?)
|
|
39
|
+
return obj.to_s if obj.has?(:proper)
|
|
40
|
+
return obj.article + ' ' + obj.to_s if obj.string?(:article)
|
|
41
|
+
return your(obj) if obj.respond_to?(:owner) && obj.owner == player
|
|
42
|
+
# PrefaceByArticle(obj, 1)
|
|
43
|
+
LowercaseTheSpaceString + obj.to_s
|
|
44
|
+
end
|
|
45
|
+
# rubocop: enable Metrics/AbcSize
|
|
46
|
+
# rubocop: enable Metrics/CyclomaticComplexity
|
|
47
|
+
|
|
48
|
+
def The(obj)
|
|
49
|
+
return obj.to_s unless obj.respond_to?(:has?)
|
|
50
|
+
return obj.to_s if obj.has?(:proper)
|
|
51
|
+
the(obj).capitalize
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def defart(obj)
|
|
55
|
+
return theirself(obj) if obj == player
|
|
56
|
+
return hisorher(player, obj) if player.descendants.include?(obj)
|
|
57
|
+
the(obj)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def indefart(obj)
|
|
61
|
+
return theirself(obj) if obj == player
|
|
62
|
+
return hisorher(player, obj) if player.descendants.include?(obj)
|
|
63
|
+
a(obj)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
LowercaseASpaceString = 'a '.freeze
|
|
67
|
+
|
|
68
|
+
# rubocop: disable Metrics/AbcSize
|
|
69
|
+
def a(obj)
|
|
70
|
+
return Inform::English::NOTHING__TX if obj.nil?
|
|
71
|
+
return PrefaceByArticle(obj, 1) if obj.is_a?(String)
|
|
72
|
+
return obj.to_s unless obj.respond_to?(:has?)
|
|
73
|
+
return obj.to_s if obj.has?(:proper)
|
|
74
|
+
return obj.article + ' ' + obj.to_s if obj.string?(:article)
|
|
75
|
+
return LowercaseSomeSpaceString + obj.to_s if obj.has?(:pluralname)
|
|
76
|
+
# PrefaceByArticle(obj, 1)
|
|
77
|
+
LowercaseASpaceString + obj.to_s
|
|
78
|
+
end
|
|
79
|
+
# rubocop: enable Metrics/AbcSize
|
|
80
|
+
|
|
81
|
+
def A(obj)
|
|
82
|
+
a(obj)&.sentence_case || obj.to_s
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def isorare(obj); IsorAre(obj); end
|
|
86
|
+
|
|
87
|
+
def itorthem(obj); ItorThem(obj); end
|
|
88
|
+
|
|
89
|
+
def thatorthose(obj); ThatorThose(obj); end
|
|
90
|
+
|
|
91
|
+
def Cthatorthose(obj); CThatorThose(obj); end
|
|
92
|
+
|
|
93
|
+
def cthatorthose(obj); CThatorThose(obj); end
|
|
94
|
+
|
|
95
|
+
def Ctheyreorthats(obj); CTheyreorThats(obj); end
|
|
96
|
+
|
|
97
|
+
def ctheyreorthats(obj); CTheyreorThats(obj); end
|
|
98
|
+
end
|
|
99
|
+
# module Articles
|
|
100
|
+
|
|
101
|
+
# Re-open the Inform::Parser module
|
|
102
|
+
module Parser
|
|
103
|
+
include Inform::Articles
|
|
104
|
+
|
|
105
|
+
VowelsOrHiPattern = %r{^([aeiou]|hi).+}.freeze
|
|
106
|
+
|
|
107
|
+
# TODO: Figure out why this isn't being called by #a(obj) above.
|
|
108
|
+
# rubocop: disable Metrics/AbcSize
|
|
109
|
+
# rubocop: disable Metrics/CyclomaticComplexity
|
|
110
|
+
# rubocop: disable Metrics/MethodLength
|
|
111
|
+
# rubocop: disable Metrics/PerceivedComplexity
|
|
112
|
+
def PrefaceByArticle(o, _acode, pluralise = false, capitalise = false)
|
|
113
|
+
log.info "wtf1 #{self.class}##{__method__}" # TODO: Remove
|
|
114
|
+
if (obj_articles = o.&:articles) && obj_articles.respond_to?(:[])
|
|
115
|
+
return obj_articles[acode] unless obj_articles[acode].nil?
|
|
116
|
+
return if pluralise
|
|
117
|
+
end
|
|
118
|
+
return if pluralise
|
|
119
|
+
if VowelsOrHiPattern.match?(o.to_s)
|
|
120
|
+
return "an #{o}".sentence_case if capitalise
|
|
121
|
+
"an #{o}"
|
|
122
|
+
else
|
|
123
|
+
return "a #{o}".sentence_case if capitalise
|
|
124
|
+
"a #{o}"
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
# rubocop: enable Metrics/AbcSize
|
|
128
|
+
# rubocop: enable Metrics/CyclomaticComplexity
|
|
129
|
+
# rubocop: enable Metrics/MethodLength
|
|
130
|
+
# rubocop: enable Metrics/PerceivedComplexity
|
|
131
|
+
end
|
|
132
|
+
# module Parser
|
|
133
|
+
|
|
134
|
+
module Verbs
|
|
135
|
+
include Inform::Articles
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
# module Inform
|
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
# frozen_string_literal: false
|
|
3
|
+
|
|
4
|
+
# Copyright Nels Nelson 2008-2023 but freely usable (see license)
|
|
5
|
+
#
|
|
6
|
+
# This file is part of the Inform Runtime.
|
|
7
|
+
#
|
|
8
|
+
# The Inform Runtime is free software: you can redistribute it and/or
|
|
9
|
+
# modify it under the terms of the GNU General Public License as published
|
|
10
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
|
11
|
+
# (at your option) any later version.
|
|
12
|
+
#
|
|
13
|
+
# The Inform Runtime is distributed in the hope that it will be useful,
|
|
14
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
15
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
16
|
+
# GNU General Public License for more details.
|
|
17
|
+
#
|
|
18
|
+
# You should have received a copy of the GNU General Public License
|
|
19
|
+
# along with the Inform Runtime. If not, see <http://www.gnu.org/licenses/>.
|
|
20
|
+
|
|
21
|
+
require 'set'
|
|
22
|
+
|
|
23
|
+
require 'method_source' # Require the method_source gem
|
|
24
|
+
|
|
25
|
+
require_relative 'articles'
|
|
26
|
+
require_relative 'color'
|
|
27
|
+
require_relative 'plurals'
|
|
28
|
+
|
|
29
|
+
# These are built-ins which may be used throughout the Inform namespace.
|
|
30
|
+
# TODO: Consider moving these into a module included in the Kernel module.
|
|
31
|
+
module Inform
|
|
32
|
+
include Inform::Articles
|
|
33
|
+
include Inform::Color
|
|
34
|
+
include Inform::Plurals
|
|
35
|
+
|
|
36
|
+
alias random rand
|
|
37
|
+
|
|
38
|
+
def dictionary
|
|
39
|
+
Inform::Dictionary
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def compass
|
|
43
|
+
InformLibrary::Compass
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def nothing
|
|
47
|
+
nil
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def content; respond_to?(:descendants) ? self.descendants : Array::Empty; end
|
|
51
|
+
alias contents content
|
|
52
|
+
|
|
53
|
+
# rubocop: disable Metrics/AbcSize
|
|
54
|
+
# rubocop: disable Metrics/CyclomaticComplexity
|
|
55
|
+
# rubocop: disable Metrics/MethodLength
|
|
56
|
+
# rubocop: disable Metrics/PerceivedComplexity
|
|
57
|
+
def with(context = nil, &block)
|
|
58
|
+
return self if block.nil?
|
|
59
|
+
existing_methods = self.singleton_methods(false)
|
|
60
|
+
|
|
61
|
+
if context.nil?
|
|
62
|
+
self.instance_eval(&block)
|
|
63
|
+
else
|
|
64
|
+
self.instance_exec(context, &block)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Only persist methods being defined just now on *this* instance
|
|
68
|
+
added = self.singleton_methods(false) - existing_methods
|
|
69
|
+
added.select! do |m|
|
|
70
|
+
self.singleton_class.instance_method(m).owner == self.singleton_class
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
if added.any?
|
|
74
|
+
persisted = self.properties.fetch(:instance_behavior, '')
|
|
75
|
+
added.each do |method_name|
|
|
76
|
+
source = method_source(method_name)
|
|
77
|
+
next if source.nil?
|
|
78
|
+
# Only support def ... end blocks
|
|
79
|
+
next unless resembles_method?(source)
|
|
80
|
+
persisted << source unless persisted.include?(source)
|
|
81
|
+
end
|
|
82
|
+
unless persisted.empty?
|
|
83
|
+
self.will_change_column(:properties) if self.respond_to?(:will_change_column)
|
|
84
|
+
self.properties[:instance_behavior] = persisted
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
self.save_changes if self.respond_to?(:save_changes)
|
|
88
|
+
self
|
|
89
|
+
end
|
|
90
|
+
# rubocop: enable Metrics/AbcSize
|
|
91
|
+
# rubocop: enable Metrics/CyclomaticComplexity
|
|
92
|
+
# rubocop: enable Metrics/MethodLength
|
|
93
|
+
# rubocop: enable Metrics/PerceivedComplexity
|
|
94
|
+
|
|
95
|
+
MethodDefinitionPattern = /\s*def\s+/.freeze
|
|
96
|
+
MethodTerminationPattern = /\s*end$/.freeze
|
|
97
|
+
|
|
98
|
+
def resembles_method?(source)
|
|
99
|
+
MethodDefinitionPattern.match?(source) && MethodTerminationPattern.match?(source)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def method_source(method_name)
|
|
103
|
+
self.singleton_class.instance_method(method_name).source
|
|
104
|
+
rescue StandardError => _e
|
|
105
|
+
nil
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def apply_instance_behavior!
|
|
109
|
+
source = self.properties[:instance_behavior]
|
|
110
|
+
return if source.nil? || source.empty?
|
|
111
|
+
return unless source.include?('def ')
|
|
112
|
+
self.instance_eval(source, "(instance_behavior for #{self.identity})", 1)
|
|
113
|
+
rescue NameError => e
|
|
114
|
+
log.warn "[InstanceBehavior] #{e.class}: #{e.message}"
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def workflags
|
|
118
|
+
Thread.current[:workflags] ||= Set.new
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def initial
|
|
122
|
+
# TODO: What is this supposed to return?
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def ofclass(klass)
|
|
126
|
+
self.is_a?(klass)
|
|
127
|
+
end
|
|
128
|
+
alias ofclass? ofclass
|
|
129
|
+
|
|
130
|
+
def provides?(prop)
|
|
131
|
+
symbolized_prop = prop.to_sym
|
|
132
|
+
return symbolized_prop if self.respond_to?(symbolized_prop)
|
|
133
|
+
downcased_prop = symbolized_prop.downcase
|
|
134
|
+
return downcased_prop if self.respond_to?(downcased_prop)
|
|
135
|
+
false
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def react_after?(action_routine = action)
|
|
139
|
+
return false if action_routine.nil?
|
|
140
|
+
self.apply_modules if self.respond_to?(:apply_modules)
|
|
141
|
+
self.provides?('react_after_' + action_routine)
|
|
142
|
+
rescue StandardError => e
|
|
143
|
+
log.error "Error checking for after reaction: #{e.message}", e
|
|
144
|
+
false
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def react_before?(action_routine = action)
|
|
148
|
+
return false if action_routine.nil?
|
|
149
|
+
self.apply_modules if self.respond_to?(:apply_modules)
|
|
150
|
+
self.provides?('react_before_' + action_routine)
|
|
151
|
+
rescue StandardError => e
|
|
152
|
+
log.error "Error checking for before reaction: #{e.message}", e
|
|
153
|
+
false
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def life?(action_routine = action)
|
|
157
|
+
return false if action_routine.nil?
|
|
158
|
+
self.apply_modules if self.respond_to?(:apply_modules)
|
|
159
|
+
self.provides?('life_' + action_routine)
|
|
160
|
+
rescue StandardError => e
|
|
161
|
+
log.error "Error checking for life reaction: #{e.message}", e
|
|
162
|
+
false
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def objectloop(*_args, &block)
|
|
166
|
+
if self.is_a?(InformLibrary)
|
|
167
|
+
Inform::Object.all.each { |o| block.call(o) }
|
|
168
|
+
elsif self.respond_to?(:descendants)
|
|
169
|
+
self.descendants.each { |o| block.call(o) }
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def getobject(id)
|
|
174
|
+
o = Inform::Object[id]
|
|
175
|
+
o.refresh
|
|
176
|
+
rescue StandardError
|
|
177
|
+
raise NoSuchObject
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def findobject(*args, &block)
|
|
181
|
+
return Inform::Object.dataset.order(:name, :id).grep(:name, *args).to_a if args.first.is_a?(Regexp)
|
|
182
|
+
Inform::Object.dataset.grep(&block).to_a
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def deadflag; @deadflag; end
|
|
186
|
+
|
|
187
|
+
def deadflag=(flag); @deadflag = flag; end
|
|
188
|
+
|
|
189
|
+
def the_time; @the_time.nil? ? 0 : @the_time; end
|
|
190
|
+
|
|
191
|
+
def the_time=(the_time); @the_time = the_time; end
|
|
192
|
+
|
|
193
|
+
def score; @score.nil? ? 0 : @score; end
|
|
194
|
+
|
|
195
|
+
def score=(score); @score = score; end
|
|
196
|
+
|
|
197
|
+
def things_score; @things_score.nil? ? 0 : @things_score; end
|
|
198
|
+
|
|
199
|
+
def things_score=(things_score); @things_score = things_score; end
|
|
200
|
+
|
|
201
|
+
def visibility_ceiling=(visibility_ceiling)
|
|
202
|
+
e = Thread.current[:event]
|
|
203
|
+
@visibility_ceiling = visibility_ceiling
|
|
204
|
+
e.visibility_ceiling = visibility_ceiling if e
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
def topic
|
|
208
|
+
consult_words
|
|
209
|
+
end
|
|
210
|
+
alias text topic
|
|
211
|
+
|
|
212
|
+
def number(x = nil)
|
|
213
|
+
return special_number1 if x.nil?
|
|
214
|
+
LanguageNumber(x)
|
|
215
|
+
''
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
def special
|
|
219
|
+
@special_word
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
def num_words
|
|
223
|
+
@words.nil? || @words.empty? ? 0 : @words.length
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
def current_word
|
|
227
|
+
@words[@wn] || ''
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
def remaining_words
|
|
231
|
+
@words[@wn..]
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
def language_pronouns
|
|
235
|
+
# TODO: Cleanup upon disconnect
|
|
236
|
+
key = self.respond_to?(:inflib) ? self.inflib : self.identity
|
|
237
|
+
LanguagePronouns[key] ||= Marshal.load(Marshal.dump(LanguagePronouns[:default]))
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
def language_descriptors
|
|
241
|
+
# TODO: Cleanup upon disconnect
|
|
242
|
+
key = self.respond_to?(:inflib) ? self.inflib : self.identity
|
|
243
|
+
LanguageDescriptors[key] ||= Marshal.load(Marshal.dump(LanguageDescriptors[:default]))
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
def light_adjusted(obj = @player)
|
|
247
|
+
# TODO: Consider performing the following in another thread or an event
|
|
248
|
+
obj.root.descendants.each do |o|
|
|
249
|
+
o.inflib.send(:AdjustLight, true) if o.has?(:creature) && !o.inflib.nil?
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
def go(obj)
|
|
254
|
+
invoke :Go, obj
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
def say(*s)
|
|
258
|
+
invoke :Say, s.flatten.sample
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
def emote(*s)
|
|
262
|
+
return consult_words if s.empty?
|
|
263
|
+
invoke :Emote, s.flatten.sample
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
def drop(obj)
|
|
267
|
+
invoke :Drop, obj
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
def search(obj)
|
|
271
|
+
invoke :Search, obj
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
def disrobe(obj)
|
|
275
|
+
invoke :Disrobe, obj
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
def quit
|
|
279
|
+
Inform::Runtime.instance.quit
|
|
280
|
+
publish :disconnect
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
# ----------------------------------------------------------------------------
|
|
284
|
+
# (From the Inform Designer's Manual)
|
|
285
|
+
# §26 Describing objects and rooms
|
|
286
|
+
# ----------------------------------------------------------------------------
|
|
287
|
+
# To print the name of such an object, Inform does the following:
|
|
288
|
+
#
|
|
289
|
+
# (1) If the short_name is a string, it's printed and that's all.
|
|
290
|
+
# (2) If it is a routine, then it is called. If it returns true, that's all.
|
|
291
|
+
# (3) The text given in the header of the object definition is printed.
|
|
292
|
+
# ----------------------------------------------------------------------------
|
|
293
|
+
def to_s
|
|
294
|
+
textual_name = self.short_name if self.respond_to?(:short_name)
|
|
295
|
+
return textual_name if textual_name.is_a?(String) # (1)
|
|
296
|
+
return if textual_name == true # (2)
|
|
297
|
+
if self.respond_to?(:name)
|
|
298
|
+
return self.name.join(' ') if self.name.respond_to?(:join)
|
|
299
|
+
return self.name.to_s # (3)
|
|
300
|
+
end
|
|
301
|
+
self.identity
|
|
302
|
+
end
|
|
303
|
+
alias to_str to_s
|
|
304
|
+
|
|
305
|
+
def classification
|
|
306
|
+
type = object_type.to_s
|
|
307
|
+
clazz = self.class.to_s
|
|
308
|
+
return type if type == clazz
|
|
309
|
+
"#{type} < #{clazz}"
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
def randomly(n = 3)
|
|
313
|
+
rand * n
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
def pause(n)
|
|
317
|
+
sleep(n)
|
|
318
|
+
:inform
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
def library_method?(method)
|
|
322
|
+
Inform::Library.methods_index.include?(method) && respond_to?(method)
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
VERB = 1
|
|
326
|
+
PLURAL = 4
|
|
327
|
+
PREPOSITION = 8
|
|
328
|
+
NOUN = 128
|
|
329
|
+
def dict_par1(w, par = 0)
|
|
330
|
+
# +128 if given a noun, +8 if a preposition, +4 if plural, +1 if a verb
|
|
331
|
+
par += NOUN if Inform::Dictionary.include?(w.to_sym)
|
|
332
|
+
par += PREPOSITION if Inform::English::Prepositions.include?(w)
|
|
333
|
+
par += PLURAL if plural?(w)
|
|
334
|
+
par += VERB unless Inform::Grammar::Verbs.lookup(w).nil?
|
|
335
|
+
par
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
protected
|
|
339
|
+
|
|
340
|
+
CommaSpacePattern = %r{[,\s]+}.freeze
|
|
341
|
+
NonAlphabeticPattern = %r{[^a-z]}i.freeze
|
|
342
|
+
|
|
343
|
+
# rubocop: disable Metrics/AbcSize
|
|
344
|
+
# rubocop: disable Metrics/CyclomaticComplexity
|
|
345
|
+
# rubocop: disable Metrics/PerceivedComplexity
|
|
346
|
+
def index_words(obj = self)
|
|
347
|
+
return unless obj.respond_to?(:name)
|
|
348
|
+
k = obj.name
|
|
349
|
+
return if k.nil? || (k.respond_to?(:empty?) && k.empty?)
|
|
350
|
+
a = k.split(CommaSpacePattern).grep_v(NonAlphabeticPattern) if k.respond_to?(:split)
|
|
351
|
+
return unless k.respond_to?(:gsub!)
|
|
352
|
+
a = k.gsub!(NonAlphabeticPattern, '') if a.nil? || a.empty?
|
|
353
|
+
Inform::Dictionary.merge(a.map(&:downcase).map(&:intern))
|
|
354
|
+
end
|
|
355
|
+
# rubocop: enable Metrics/AbcSize
|
|
356
|
+
# rubocop: enable Metrics/CyclomaticComplexity
|
|
357
|
+
# rubocop: enable Metrics/PerceivedComplexity
|
|
358
|
+
end
|
|
359
|
+
# module Inform
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
# frozen_string_literal: false
|
|
3
|
+
|
|
4
|
+
# Copyright Nels Nelson 2008-2023 but freely usable (see license)
|
|
5
|
+
#
|
|
6
|
+
# This file is part of the Inform Runtime.
|
|
7
|
+
#
|
|
8
|
+
# The Inform Runtime is free software: you can redistribute it and/or
|
|
9
|
+
# modify it under the terms of the GNU General Public License as published
|
|
10
|
+
# by the Free Software Foundation, either version 3 of the License, or
|
|
11
|
+
# (at your option) any later version.
|
|
12
|
+
#
|
|
13
|
+
# The Inform Runtime is distributed in the hope that it will be useful,
|
|
14
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
15
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
16
|
+
# GNU General Public License for more details.
|
|
17
|
+
#
|
|
18
|
+
# You should have received a copy of the GNU General Public License
|
|
19
|
+
# along with the Inform Runtime. If not, see <http://www.gnu.org/licenses/>.
|
|
20
|
+
|
|
21
|
+
# The Inform module
|
|
22
|
+
module Inform
|
|
23
|
+
# The Color module
|
|
24
|
+
module Color
|
|
25
|
+
StyleCodes = {
|
|
26
|
+
plain: [
|
|
27
|
+
"\e[0m", "\e[0m"],
|
|
28
|
+
bold: [
|
|
29
|
+
"\e[1m", "\e[22m"],
|
|
30
|
+
italic: [
|
|
31
|
+
"\e[3m", "\e[23m"],
|
|
32
|
+
underline: [
|
|
33
|
+
"\e[4m", "\e[24m"],
|
|
34
|
+
blink: [
|
|
35
|
+
"\e[5m", "\e[25m"],
|
|
36
|
+
flash: [
|
|
37
|
+
"\e[6m", "\e[26m"],
|
|
38
|
+
inverse: [
|
|
39
|
+
"\e[7m", "\e[27m"],
|
|
40
|
+
hidden: [
|
|
41
|
+
"\e[8m", "\e[28m"],
|
|
42
|
+
strikethrough: [
|
|
43
|
+
"\e[9m", "\e[29m"]
|
|
44
|
+
}.freeze
|
|
45
|
+
|
|
46
|
+
ColorCodes = {
|
|
47
|
+
default: [
|
|
48
|
+
"\e[0m", "\e[0m"],
|
|
49
|
+
black: [
|
|
50
|
+
"\e[30m", "\e[39m"],
|
|
51
|
+
black_on_white: [
|
|
52
|
+
"\e[30m", "\e[39m"],
|
|
53
|
+
red: [
|
|
54
|
+
"\e[31m", "\e[39m"],
|
|
55
|
+
green: [
|
|
56
|
+
"\e[32m", "\e[39m"],
|
|
57
|
+
yellow: [
|
|
58
|
+
"\e[33m", "\e[39m"],
|
|
59
|
+
blue: [
|
|
60
|
+
"\e[34m", "\e[39m"],
|
|
61
|
+
purple: [
|
|
62
|
+
"\e[35m", "\e[39m"],
|
|
63
|
+
magenta: [
|
|
64
|
+
"\e[35m", "\e[39m"],
|
|
65
|
+
cyan: [
|
|
66
|
+
"\e[36m", "\e[39m"],
|
|
67
|
+
white: [
|
|
68
|
+
"\e[37m", "\e[39m"]
|
|
69
|
+
}.freeze
|
|
70
|
+
|
|
71
|
+
BackgroundColorCodes = {
|
|
72
|
+
default: [
|
|
73
|
+
"\e[0m", "\e[0m"],
|
|
74
|
+
black: [
|
|
75
|
+
"\e[40m", "\e[49m"],
|
|
76
|
+
red: [
|
|
77
|
+
"\e[41m", "\e[49m"],
|
|
78
|
+
green: [
|
|
79
|
+
"\e[42m", "\e[49m"],
|
|
80
|
+
yellow: [
|
|
81
|
+
"\e[43m", "\e[49m"],
|
|
82
|
+
blue: [
|
|
83
|
+
"\e[44m", "\e[49m"],
|
|
84
|
+
purple: [
|
|
85
|
+
"\e[45m", "\e[49m"],
|
|
86
|
+
magenta: [
|
|
87
|
+
"\e[45m", "\e[49m"],
|
|
88
|
+
cyan: [
|
|
89
|
+
"\e[46m", "\e[49m"],
|
|
90
|
+
white: [
|
|
91
|
+
"\e[47m", "\e[49m"]
|
|
92
|
+
}.freeze
|
|
93
|
+
|
|
94
|
+
# Text style and color for terminals
|
|
95
|
+
def style(style, text = nil)
|
|
96
|
+
code = (StyleCodes[style] || StyleCodes[:plain]).first
|
|
97
|
+
return code + text + (StyleCodes[style] || StyleCodes[:plain]).last unless text.nil?
|
|
98
|
+
print code
|
|
99
|
+
end
|
|
100
|
+
def un_style(style)
|
|
101
|
+
print((StyleCodes[style] || StyleCodes[:plain]).last)
|
|
102
|
+
end
|
|
103
|
+
alias unstyle un_style
|
|
104
|
+
def color(color, text = nil)
|
|
105
|
+
code = (ColorCodes[color] || ColorCodes[:default]).first
|
|
106
|
+
return code + text + (ColorCodes[color] || ColorCodes[:default]).last unless text.nil?
|
|
107
|
+
print code
|
|
108
|
+
end
|
|
109
|
+
def un_color(color)
|
|
110
|
+
print((ColorCodes[color] || ColorCodes[:default]).last)
|
|
111
|
+
end
|
|
112
|
+
alias uncolor un_color
|
|
113
|
+
def background_color(color, text = nil)
|
|
114
|
+
code = (BackgroundColorCodes[color] || BackgroundColorCodes[:default]).first
|
|
115
|
+
return code + text + (BackgroundColorCodes[color] || BackgroundColorCodes[:default]).last unless text.nil?
|
|
116
|
+
print code
|
|
117
|
+
end
|
|
118
|
+
alias bgcolor background_color
|
|
119
|
+
def un_background_color(color)
|
|
120
|
+
print((BackgroundColorCodes[color] || BackgroundColorCodes[:default]).last)
|
|
121
|
+
end
|
|
122
|
+
alias unbgcolor un_background_color
|
|
123
|
+
|
|
124
|
+
NearestColor = {
|
|
125
|
+
red: %i[
|
|
126
|
+
crimson brick salmon coral],
|
|
127
|
+
yellow: %i[
|
|
128
|
+
golden orange],
|
|
129
|
+
green: %i[
|
|
130
|
+
seagreen teal forestgreen],
|
|
131
|
+
blue: %i[
|
|
132
|
+
aqua cyan skyblue turqoise],
|
|
133
|
+
magenta: %i[
|
|
134
|
+
lavender fuchsia indigo orchid plum purple violet]
|
|
135
|
+
}.freeze
|
|
136
|
+
|
|
137
|
+
def nearest_color(color)
|
|
138
|
+
colors = NearestColor.select { |_, v| v.include?(color) }
|
|
139
|
+
return colors.first.first unless colors.empty?
|
|
140
|
+
:white
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
# module Color
|
|
144
|
+
end
|
|
145
|
+
# module Inform
|