inform6lib 0.1.2 → 0.1.3
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 +4 -4
- data/lib/inform/English.h.rb +31 -63
- data/lib/inform/Parser.h.rb +3 -3
- data/lib/inform/VerbLib.h.rb +1 -1
- data/lib/inform/infix.h.rb +1 -1
- data/lib/inform/parserm.h.rb +399 -317
- data/lib/inform/verblibm.h.rb +170 -129
- metadata +3 -3
data/lib/inform/parserm.h.rb
CHANGED
|
@@ -60,7 +60,6 @@
|
|
|
60
60
|
# which supports the referencing of Special Global Variables like
|
|
61
61
|
# $LAST_MATCH_INFO by their screaming snake case names.
|
|
62
62
|
require 'English'
|
|
63
|
-
require 'set'
|
|
64
63
|
|
|
65
64
|
require_relative 'linklpa.h'
|
|
66
65
|
|
|
@@ -249,7 +248,7 @@ module Parser
|
|
|
249
248
|
if !defined?(MAX_TIMERS)
|
|
250
249
|
MAX_TIMERS = 32 # Max number timers/daemons active at once
|
|
251
250
|
end # if !defined?(MAX_TIMERS)
|
|
252
|
-
@the_timers = [
|
|
251
|
+
@the_timers = []
|
|
253
252
|
@active_timers # Number of timers/daemons actives
|
|
254
253
|
|
|
255
254
|
@score # The current score
|
|
@@ -540,22 +539,22 @@ module Parser
|
|
|
540
539
|
@selfobj ||= SelfObj
|
|
541
540
|
end
|
|
542
541
|
|
|
543
|
-
def selfobj=(
|
|
544
|
-
@selfobj =
|
|
542
|
+
def selfobj=(obj)
|
|
543
|
+
@selfobj = obj
|
|
545
544
|
end
|
|
546
545
|
|
|
547
546
|
InitalState = Struct.new(:memo).new
|
|
548
547
|
|
|
549
548
|
def self.initial_state
|
|
550
|
-
InitalState.memo ||= Inform::Parser.instance_variables.
|
|
551
|
-
|
|
549
|
+
InitalState.memo ||= Inform::Parser.instance_variables.to_h do |variable|
|
|
550
|
+
[variable, Inform::Parser.instance_variable_get(variable)]
|
|
552
551
|
end
|
|
553
552
|
end
|
|
554
553
|
|
|
555
554
|
def initialize_state
|
|
556
555
|
DidScopeAction.clear # TODO: Remove
|
|
557
|
-
Inform::Parser.initial_state.each_pair do |
|
|
558
|
-
self.instance_variable_set(
|
|
556
|
+
Inform::Parser.initial_state.each_pair do |key, value|
|
|
557
|
+
self.instance_variable_set(key, value)
|
|
559
558
|
end
|
|
560
559
|
end
|
|
561
560
|
|
|
@@ -816,7 +815,9 @@ module Parser
|
|
|
816
815
|
# Note that there are three different places where a return can happen.
|
|
817
816
|
# ----------------------------------------------------------------------------
|
|
818
817
|
|
|
819
|
-
|
|
818
|
+
QuotesSayCommandPattern = %r{^['"]}
|
|
819
|
+
ConversationStarterPattern = %r{\w+, }
|
|
820
|
+
WordOrCommaSplitPattern = %r{\s+|(?=,)|(?<=,)}
|
|
820
821
|
|
|
821
822
|
def Parser__parse
|
|
822
823
|
@meta = false
|
|
@@ -843,23 +844,28 @@ module Parser
|
|
|
843
844
|
|
|
844
845
|
if @held_back_mode
|
|
845
846
|
@held_back_mode = false
|
|
846
|
-
|
|
847
|
+
return ReParse()
|
|
847
848
|
end
|
|
848
849
|
|
|
849
850
|
# Handle the apostrophe shorthand for the Say command
|
|
850
|
-
@input = "say '#{@input[1..]}'" if @input
|
|
851
|
+
@input = "say '#{@input[1..]}'" if QuotesSayCommandPattern.match?(@input)
|
|
851
852
|
|
|
852
853
|
# Get the words from the player's input
|
|
853
|
-
@words = @input.split
|
|
854
|
+
# @words = @input.split
|
|
855
|
+
@words = @input.split(WordOrCommaSplitPattern)
|
|
854
856
|
|
|
855
|
-
|
|
857
|
+
ReParse()
|
|
858
|
+
end
|
|
859
|
+
# def Parser__parse
|
|
856
860
|
|
|
861
|
+
def ReParse
|
|
857
862
|
@parser_inflection = :name
|
|
858
863
|
|
|
859
864
|
# Initially assume the command is aimed at the player, and the verb
|
|
860
865
|
# is the first word
|
|
861
866
|
|
|
862
867
|
# num_words = WordCount()
|
|
868
|
+
@num_words = @words.length
|
|
863
869
|
@wn = 0 # Our words "buffer" is indexed from 0, unlike Inform
|
|
864
870
|
|
|
865
871
|
if defined? LanguageToInformese
|
|
@@ -912,14 +918,19 @@ module Parser
|
|
|
912
918
|
@location ||= @actors_location # TODO: Necessary?
|
|
913
919
|
@usual_grammar_after = nil
|
|
914
920
|
|
|
915
|
-
|
|
921
|
+
AlmostReParse()
|
|
922
|
+
end
|
|
923
|
+
# def ReParse
|
|
916
924
|
|
|
925
|
+
def AlmostReParse
|
|
917
926
|
@scope_token = nil
|
|
918
927
|
@action_to_be = nil
|
|
919
928
|
|
|
920
|
-
|
|
929
|
+
BeginCommand()
|
|
930
|
+
end
|
|
921
931
|
|
|
922
|
-
|
|
932
|
+
def BeginCommand()
|
|
933
|
+
# Begin from what we currently think is the verb word
|
|
923
934
|
|
|
924
935
|
@wn = @verb_wordnum
|
|
925
936
|
# @verb_word = NextWordStopped() # TODO: FIXME?
|
|
@@ -938,7 +949,7 @@ module Parser
|
|
|
938
949
|
|
|
939
950
|
@verb_word = AGAIN1__WD if @verb_word == AGAIN2__WD || @verb_word == AGAIN3__WD
|
|
940
951
|
if @verb_word == AGAIN1__WD
|
|
941
|
-
raise
|
|
952
|
+
raise RepeatedCommand if @actor != @player
|
|
942
953
|
raise NothingToRepeat if history.empty?
|
|
943
954
|
@input = history.last
|
|
944
955
|
@words = @input.split
|
|
@@ -956,8 +967,6 @@ module Parser
|
|
|
956
967
|
# return DoOops()
|
|
957
968
|
end
|
|
958
969
|
|
|
959
|
-
initialize_state
|
|
960
|
-
|
|
961
970
|
if @match_list then @match_list.clear else @match_list = [] end
|
|
962
971
|
if @multiple_object then @multiple_object.clear else @multiple_object = [] end
|
|
963
972
|
if @pattern then @pattern.clear else @pattern = [] end
|
|
@@ -1005,7 +1014,7 @@ module Parser
|
|
|
1005
1014
|
end # DEBUG
|
|
1006
1015
|
@wn = @verb_wordnum; @indef_mode = false; @token_filter = nil
|
|
1007
1016
|
l = NounDomain(Compass)
|
|
1008
|
-
#
|
|
1017
|
+
# return ReParse() if l == REPARSE_CODE
|
|
1009
1018
|
|
|
1010
1019
|
if l
|
|
1011
1020
|
# If it is a direction, send back the results:
|
|
@@ -1031,41 +1040,23 @@ module Parser
|
|
|
1031
1040
|
# tell the wizard that she is an idiot.)
|
|
1032
1041
|
|
|
1033
1042
|
if @actor == @player
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
else
|
|
1039
|
-
@verb = UnknownVerb(@verb)
|
|
1040
|
-
if @verb.nil?
|
|
1041
|
-
@best_etype = VerbUnrecognized
|
|
1042
|
-
raise @best_etype
|
|
1043
|
-
else
|
|
1044
|
-
log.debug "jump VerbAccepted"
|
|
1045
|
-
# jump VerbAccepted
|
|
1046
|
-
end
|
|
1043
|
+
j = 2
|
|
1044
|
+
while j <= @num_words
|
|
1045
|
+
i = NextWord(); j += 1
|
|
1046
|
+
return Conversation() if i == @comma_word
|
|
1047
1047
|
end
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
raise @best_etype
|
|
1048
|
+
@verb = UnknownVerb(@verb)
|
|
1049
|
+
return VerbAccepted() unless @verb.nil?
|
|
1051
1050
|
end
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
@actor = l
|
|
1056
|
-
@actors_location = ScopeCeiling(l)
|
|
1057
|
-
if defined?(DEBUG)
|
|
1058
|
-
if @parser_trace >= 1
|
|
1059
|
-
println "[Actor is " + the(@actor) + " in " + @actors_location + "]"
|
|
1060
|
-
end
|
|
1061
|
-
end # DEBUG
|
|
1062
|
-
return true
|
|
1051
|
+
@best_etype = VerbUnrecognized
|
|
1052
|
+
return GiveError()
|
|
1053
|
+
# raise @best_etype
|
|
1063
1054
|
end
|
|
1064
|
-
# of first-word-not-a-verb
|
|
1055
|
+
# end of first-word-not-a-verb
|
|
1065
1056
|
|
|
1066
1057
|
VerbAccepted()
|
|
1067
1058
|
end
|
|
1068
|
-
# def
|
|
1059
|
+
# def BeginCommand
|
|
1069
1060
|
|
|
1070
1061
|
############################################################################
|
|
1071
1062
|
#
|
|
@@ -1143,46 +1134,41 @@ module Parser
|
|
|
1143
1134
|
|
|
1144
1135
|
return true
|
|
1145
1136
|
end
|
|
1146
|
-
# def
|
|
1137
|
+
# def VerbAccepted
|
|
1147
1138
|
|
|
1148
1139
|
# NextWord nudges the word number wn on by one each time, so we've now
|
|
1149
1140
|
# advanced past a comma. (A comma is a word all on its own in the table.)
|
|
1150
1141
|
|
|
1151
1142
|
def Conversation
|
|
1152
|
-
j = @wn
|
|
1153
|
-
if j == 1
|
|
1154
|
-
raise UnexpectedComma
|
|
1155
|
-
end
|
|
1143
|
+
j = @wn
|
|
1144
|
+
raise UnexpectedComma if j == 1
|
|
1156
1145
|
|
|
1157
1146
|
# Use NounDomain (in the context of "animate creature") to see if the
|
|
1158
1147
|
# words make sense as the name of someone held or nearby
|
|
1159
1148
|
|
|
1160
|
-
@wn =
|
|
1149
|
+
@wn = 0; @lookahead = :held
|
|
1161
1150
|
@scope_reason = TALKING_REASON
|
|
1162
1151
|
l = NounDomain(@player,@actors_location,6)
|
|
1163
1152
|
@scope_reason = PARSING_REASON
|
|
1164
1153
|
throw :ReParse if l == REPARSE_CODE
|
|
1165
|
-
raise MissingAddressee if l ==
|
|
1154
|
+
raise MissingAddressee if l == false
|
|
1166
1155
|
|
|
1167
|
-
Conversation2()
|
|
1156
|
+
Conversation2(l, j)
|
|
1168
1157
|
end
|
|
1169
1158
|
|
|
1170
|
-
def Conversation2
|
|
1159
|
+
def Conversation2(l, j)
|
|
1171
1160
|
|
|
1172
1161
|
# The object addressed must at least be "talkable" if not actually "animate"
|
|
1173
1162
|
# (the distinction allows, for instance, a microphone to be spoken to,
|
|
1174
1163
|
# without the parser thinking that the microphone is human).
|
|
1175
1164
|
|
|
1176
|
-
if l.hasnt? :animate, :talkable
|
|
1177
|
-
raise InanimateAddressee
|
|
1178
|
-
end
|
|
1165
|
+
raise InanimateAddressee if l.hasnt? :animate, :talkable
|
|
1179
1166
|
|
|
1180
1167
|
# Check that there aren't any mystery words between the end of the person's
|
|
1181
1168
|
# name and the comma (eg, throw out "dwarf sdfgsdgs, go north").
|
|
1182
1169
|
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
end
|
|
1170
|
+
@wn += 1
|
|
1171
|
+
raise SpeechImpediment if @wn != j
|
|
1186
1172
|
|
|
1187
1173
|
# The player has now successfully named someone. Adjust "him", "her", "it":
|
|
1188
1174
|
|
|
@@ -1191,15 +1177,14 @@ module Parser
|
|
|
1191
1177
|
# Set the global variable "actor", adjust the number of the first word,
|
|
1192
1178
|
# and begin parsing again from there.
|
|
1193
1179
|
|
|
1194
|
-
@verb_wordnum = j
|
|
1180
|
+
@verb_wordnum = j
|
|
1195
1181
|
|
|
1196
1182
|
# Stop things like "me, again":
|
|
1197
1183
|
|
|
1198
1184
|
if l == @player
|
|
1199
1185
|
@wn = @verb_wordnum
|
|
1200
1186
|
if [AGAIN1__WD, AGAIN2__WD, AGAIN3__WD].include?(NextWordStopped())
|
|
1201
|
-
|
|
1202
|
-
jump ReType
|
|
1187
|
+
raise RepeatedCommand
|
|
1203
1188
|
end
|
|
1204
1189
|
end
|
|
1205
1190
|
|
|
@@ -1316,7 +1301,8 @@ module Parser
|
|
|
1316
1301
|
prepositions = @line_token[@pcount].split(/\//).map { |s| s[1..-2] }
|
|
1317
1302
|
@pcount += 1 while @line_ttype[@pcount] == :preposition
|
|
1318
1303
|
|
|
1319
|
-
if ElementaryTokens.include?(@line_ttype[@pcount]) &&
|
|
1304
|
+
if ElementaryTokens.include?(@line_ttype[@pcount]) &&
|
|
1305
|
+
@line_tdata[@pcount] == :noun
|
|
1320
1306
|
|
|
1321
1307
|
# Advance past the last preposition
|
|
1322
1308
|
|
|
@@ -1402,6 +1388,7 @@ module Parser
|
|
|
1402
1388
|
@scope_reason = PARSING_REASON
|
|
1403
1389
|
AnalyseToken(token)
|
|
1404
1390
|
|
|
1391
|
+
# TODO: FIXME
|
|
1405
1392
|
# if @action_to_be == :AskTo && ElementaryTokens.include?(@found_ttype) &&
|
|
1406
1393
|
# @found_tdata == :topic
|
|
1407
1394
|
# l = @results[2]
|
|
@@ -1414,7 +1401,8 @@ module Parser
|
|
|
1414
1401
|
|
|
1415
1402
|
if defined?(DEBUG) && @parser_trace >= 10
|
|
1416
1403
|
new_line
|
|
1417
|
-
println "Parsing the current word '#{current_word}'
|
|
1404
|
+
println "Parsing the current word '#{current_word}' " +
|
|
1405
|
+
"as a #{@found_ttype} in this grammar:"
|
|
1418
1406
|
println grammar.to_s
|
|
1419
1407
|
println ">>Before invoking ParseToken(#{@found_ttype})..."
|
|
1420
1408
|
println ">>...The found token data is #{@found_tdata}"
|
|
@@ -1603,7 +1591,8 @@ module Parser
|
|
|
1603
1591
|
# We continue the outer "for" loop, trying the next line in the grammar.
|
|
1604
1592
|
|
|
1605
1593
|
@best_etype = @etype if @etype > @best_etype
|
|
1606
|
-
@nextbest_etype = @etype if @etype != AskScope &&
|
|
1594
|
+
@nextbest_etype = @etype if @etype != AskScope &&
|
|
1595
|
+
!@etype.nil? && @etype > @nextbest_etype
|
|
1607
1596
|
|
|
1608
1597
|
# ...unless the line was something like "take all" which failed because
|
|
1609
1598
|
# nothing matched the "all", in which case we stop and give an error now.
|
|
@@ -1615,14 +1604,17 @@ module Parser
|
|
|
1615
1604
|
|
|
1616
1605
|
# The grammar is exhausted: every line has failed to match.
|
|
1617
1606
|
|
|
1607
|
+
GiveError()
|
|
1608
|
+
end
|
|
1609
|
+
# def BestGrammar
|
|
1610
|
+
|
|
1618
1611
|
############################################################################
|
|
1619
1612
|
#
|
|
1620
1613
|
# H: Cheaply parse otherwise unrecognised conversation and return
|
|
1621
1614
|
#
|
|
1622
1615
|
############################################################################
|
|
1623
1616
|
|
|
1624
|
-
|
|
1625
|
-
|
|
1617
|
+
def GiveError
|
|
1626
1618
|
if defined?(DEBUG) && @parser_trace >= 10
|
|
1627
1619
|
println ">>@etype is #{@etype}"
|
|
1628
1620
|
println ">>@best_etype is #{@best_etype}"
|
|
@@ -1633,26 +1625,25 @@ module Parser
|
|
|
1633
1625
|
# If the command was addressed to somebody else (eg, "dwarf, sfgh") then
|
|
1634
1626
|
# it is taken as conversation which the parser has no business in disallowing.
|
|
1635
1627
|
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
# end
|
|
1628
|
+
if @actor != @player
|
|
1629
|
+
unless @usual_grammar_after.nil?
|
|
1630
|
+
@verb_wordnum = @usual_grammar_after
|
|
1631
|
+
return AlmostReParse()
|
|
1632
|
+
end
|
|
1633
|
+
@wn = @verb_wordnum
|
|
1634
|
+
@special_word = NextWord()
|
|
1635
|
+
if @special_word == @comma_word
|
|
1636
|
+
@special_word = NextWord()
|
|
1637
|
+
@verb_wordnum += 1
|
|
1638
|
+
end
|
|
1639
|
+
@special_number = TryNumber(@verb_wordnum)
|
|
1640
|
+
@results[0] = :NotUnderstood
|
|
1641
|
+
@results[1] = 2
|
|
1642
|
+
@results[2] = 1; @special_number1 = @special_word
|
|
1643
|
+
@results[3] = @actor
|
|
1644
|
+
@consult_from = @verb_wordnum; @consult_words = @num_words-@consult_from+1
|
|
1645
|
+
return true
|
|
1646
|
+
end
|
|
1656
1647
|
|
|
1657
1648
|
############################################################################
|
|
1658
1649
|
#
|
|
@@ -1679,7 +1670,7 @@ module Parser
|
|
|
1679
1670
|
# ...being careful not to go all the way back, to avoid infinite repetition
|
|
1680
1671
|
# of a deferred command causing an error.
|
|
1681
1672
|
end
|
|
1682
|
-
# def
|
|
1673
|
+
# def GiveError
|
|
1683
1674
|
|
|
1684
1675
|
############################################################################
|
|
1685
1676
|
#
|
|
@@ -1896,7 +1887,7 @@ module Parser
|
|
|
1896
1887
|
# (F) Return the conclusion of parsing an object list
|
|
1897
1888
|
# ----------------------------------------------------------------------------
|
|
1898
1889
|
|
|
1899
|
-
CommaWordPattern = %r{,$}
|
|
1890
|
+
CommaWordPattern = %r{,$}
|
|
1900
1891
|
|
|
1901
1892
|
# rubocop: disable Layout/EmptyLinesAroundBlockBody
|
|
1902
1893
|
def ParseToken(given_ttype, given_tdata, token_n, token)
|
|
@@ -2041,7 +2032,10 @@ module Parser
|
|
|
2041
2032
|
|
|
2042
2033
|
end
|
|
2043
2034
|
|
|
2044
|
-
|
|
2035
|
+
# TODO: Remove (2026-08-21)
|
|
2036
|
+
# token = given_ttype
|
|
2037
|
+
# TODO: Test
|
|
2038
|
+
token = given_tdata
|
|
2045
2039
|
prev_indef_wanted = 0
|
|
2046
2040
|
|
|
2047
2041
|
############################################################################
|
|
@@ -2116,7 +2110,9 @@ module Parser
|
|
|
2116
2110
|
end
|
|
2117
2111
|
end
|
|
2118
2112
|
|
|
2119
|
-
if [ME1__WD, ME2__WD, ME3__WD].include?(o)
|
|
2113
|
+
if [ME1__WD, ME2__WD, ME3__WD].include?(o)
|
|
2114
|
+
@pronoun_word = o; @pronoun_obj = selfobj
|
|
2115
|
+
end
|
|
2120
2116
|
|
|
2121
2117
|
@allow_plurals = true; desc_wn = @wn;
|
|
2122
2118
|
|
|
@@ -2197,7 +2193,8 @@ module Parser
|
|
|
2197
2193
|
@wn = desc_wn
|
|
2198
2194
|
throw :TryAgain2
|
|
2199
2195
|
end
|
|
2200
|
-
@etype = CannotUnderstandSentence if @multiflag &&
|
|
2196
|
+
@etype = CannotUnderstandSentence if @multiflag &&
|
|
2197
|
+
[UnexpectedMultiple, TooFew].include?(@etype)
|
|
2201
2198
|
@etype = CantSee()
|
|
2202
2199
|
return FailToken(desc_wn, prev_indef_wanted)
|
|
2203
2200
|
end # Choose best error
|
|
@@ -2749,7 +2746,8 @@ module Parser
|
|
|
2749
2746
|
next unless @pattern[j]
|
|
2750
2747
|
|
|
2751
2748
|
if defined?(DEBUG)
|
|
2752
|
-
println "[Gluing in inference with pattern code " +
|
|
2749
|
+
println "[Gluing in inference with pattern code " +
|
|
2750
|
+
@pattern[j] + "]" if @parser_trace >= 5
|
|
2753
2751
|
end # DEBUG
|
|
2754
2752
|
|
|
2755
2753
|
# Conveniently, parse2[1] is the first word in both ZCODE and GLULX.
|
|
@@ -2975,7 +2973,8 @@ module Parser
|
|
|
2975
2973
|
end
|
|
2976
2974
|
@multi_context = context
|
|
2977
2975
|
if defined?(DEBUG)
|
|
2978
|
-
println " Made multiple object of size
|
|
2976
|
+
println " Made multiple object of size " +
|
|
2977
|
+
"#{@multiple_object.length}]" if @parser_trace >= 4
|
|
2979
2978
|
end # DEBUG
|
|
2980
2979
|
return 1
|
|
2981
2980
|
end
|
|
@@ -3007,7 +3006,8 @@ module Parser
|
|
|
3007
3006
|
println " Grouped into #{n} possibilities by name:"
|
|
3008
3007
|
for i in (0...@number_matched)
|
|
3009
3008
|
if @match_classes[i] > 0
|
|
3010
|
-
print " " + The(@match_list[i]) +
|
|
3009
|
+
print " " + The(@match_list[i]) +
|
|
3010
|
+
" (#{@match_list[i].object_id}) --- group #{@match_classes[i]}\n"
|
|
3011
3011
|
end
|
|
3012
3012
|
end
|
|
3013
3013
|
end
|
|
@@ -3097,7 +3097,8 @@ module Parser
|
|
|
3097
3097
|
# entries which fail the basic requirements of the descriptors.
|
|
3098
3098
|
# ----------------------------------------------------------------------------
|
|
3099
3099
|
|
|
3100
|
-
def ScoreMatchL(context, match_list = [], match_scores = [],
|
|
3100
|
+
def ScoreMatchL(context, match_list = [], match_scores = [],
|
|
3101
|
+
number_matched = 0, threshold = 0)
|
|
3101
3102
|
threshold += 1 if (@indef_type & OTHER_BIT) != 0
|
|
3102
3103
|
threshold += 1 if (@indef_type & MY_BIT) != 0
|
|
3103
3104
|
threshold += 1 if (@indef_type & THAT_BIT) != 0
|
|
@@ -3129,7 +3130,8 @@ module Parser
|
|
|
3129
3130
|
for i in (0...number_matched)
|
|
3130
3131
|
obj = match_list[i]; its_owner = parent(obj); its_score = 0; met = 0
|
|
3131
3132
|
|
|
3132
|
-
# met+=1 if (@indef_type & OTHER_BIT) != 0 &&
|
|
3133
|
+
# met+=1 if (@indef_type & OTHER_BIT) != 0 &&
|
|
3134
|
+
# obj != @itobj && obj != @himobj && obj != @herobj
|
|
3133
3135
|
met += 1 if (@indef_type & MY_BIT) != 0 && (its_owner == @actor)
|
|
3134
3136
|
met += 1 if (@indef_type & THAT_BIT) != 0 && (its_owner == @actors_location)
|
|
3135
3137
|
met += 1 if (@indef_type & LIT_BIT) != 0 && obj.has?(:light)
|
|
@@ -3209,7 +3211,9 @@ module Parser
|
|
|
3209
3211
|
if defined?(DEBUG)
|
|
3210
3212
|
if @parser_trace >= 4
|
|
3211
3213
|
if best < 0 then println " Best guess ran out of choices"
|
|
3212
|
-
else
|
|
3214
|
+
else
|
|
3215
|
+
println " Best guess " + the(@match_list[earliest]) +
|
|
3216
|
+
" (#{@match_list[earliest]})"
|
|
3213
3217
|
end
|
|
3214
3218
|
end
|
|
3215
3219
|
end # DEBUG
|
|
@@ -3301,7 +3305,8 @@ module Parser
|
|
|
3301
3305
|
|
|
3302
3306
|
# def PrintInferredCommand(from = 0)
|
|
3303
3307
|
# singleton_noun = false
|
|
3304
|
-
# if from != 0 && from == (@pcount-1) &&
|
|
3308
|
+
# if from != 0 && from == (@pcount-1) &&
|
|
3309
|
+
# @pattern[from].object? # > 1 && @pattern[from] < REPARSE_CODE
|
|
3305
3310
|
# singleton_noun = true
|
|
3306
3311
|
# end
|
|
3307
3312
|
|
|
@@ -3310,7 +3315,8 @@ module Parser
|
|
|
3310
3315
|
|
|
3311
3316
|
# def PrintInferredCommand(from = nil)
|
|
3312
3317
|
# singleton_noun = false
|
|
3313
|
-
# if from != 0 && from == @pcount-1 &&
|
|
3318
|
+
# if from != 0 && from == @pcount-1 &&
|
|
3319
|
+
# @pattern[from].object? # && @pattern[from] < REPARSE_CODE
|
|
3314
3320
|
# singleton_noun = true
|
|
3315
3321
|
# end
|
|
3316
3322
|
# if singleton_noun == true
|
|
@@ -3593,10 +3599,7 @@ module Parser
|
|
|
3593
3599
|
if @parser_trace >= 6
|
|
3594
3600
|
println "[DSA on " + the(thing) + " with reason = " + scope_reason.to_s +
|
|
3595
3601
|
" p1 = #{@parser_one} p2 = #{@parser_two}]"
|
|
3596
|
-
|
|
3597
|
-
if name(thing) == 'Nels'
|
|
3598
|
-
caller.each { |t| println t }
|
|
3599
|
-
elsif DidScopeAction[thing][scope_reason] > 1
|
|
3602
|
+
if DidScopeAction[thing][scope_reason] > 1
|
|
3600
3603
|
println "Did DoScopeAction(#{thing}) with reason = #{scope_reason} more than once!"
|
|
3601
3604
|
caller.each { |t| println t }
|
|
3602
3605
|
end
|
|
@@ -3604,13 +3607,13 @@ module Parser
|
|
|
3604
3607
|
end # DEBUG
|
|
3605
3608
|
case scope_reason
|
|
3606
3609
|
when REACT_BEFORE_REASON
|
|
3607
|
-
return unless thing.react_before?(action)
|
|
3610
|
+
return unless thing.react_before?(@action)
|
|
3608
3611
|
if defined?(DEBUG)
|
|
3609
3612
|
println "[Considering react_before for " + the(thing) + "]" if @parser_trace >= 2
|
|
3610
3613
|
end
|
|
3611
3614
|
@parser_one ||= RunRoutines(thing, :react_before)
|
|
3612
3615
|
when REACT_AFTER_REASON
|
|
3613
|
-
return unless thing.react_after?(action)
|
|
3616
|
+
return unless thing.react_after?(@action)
|
|
3614
3617
|
if defined?(DEBUG)
|
|
3615
3618
|
println "[Considering react_after for " + the(thing) + "]" if @parser_trace >= 2
|
|
3616
3619
|
end # DEBUG
|
|
@@ -3790,7 +3793,8 @@ module Parser
|
|
|
3790
3793
|
println ">>...Matches are [#{matches_}] ([#{object_ids_}])"
|
|
3791
3794
|
end
|
|
3792
3795
|
println ">>...No matches yet" if @match_list.empty?
|
|
3793
|
-
println ">>...Matched by #{@match_length} word" +
|
|
3796
|
+
println ">>...Matched by #{@match_length} word" +
|
|
3797
|
+
(!@match_length.nil? && @match_length == 1 ? 's' : '')
|
|
3794
3798
|
println ">>...Match is #{obj} (#{obj.object_id})"
|
|
3795
3799
|
already_in_list = @match_list.include?(obj) ? 'Yes' : 'No'
|
|
3796
3800
|
println ">>...Is object id #{obj.object_id} already in the match list? #{already_in_list}"
|
|
@@ -3866,7 +3870,8 @@ module Parser
|
|
|
3866
3870
|
|
|
3867
3871
|
def TryGivenObject(obj)
|
|
3868
3872
|
if defined?(DEBUG)
|
|
3869
|
-
println " Trying " + the(obj) +
|
|
3873
|
+
println " Trying " + the(obj) +
|
|
3874
|
+
" (#{obj.object_id}) at word #{@wn + 1}" if @parser_trace >= 5
|
|
3870
3875
|
end # DEBUG
|
|
3871
3876
|
|
|
3872
3877
|
@dict_flags_of_noun = 0
|
|
@@ -4060,7 +4065,7 @@ module Parser
|
|
|
4060
4065
|
return NextWord()
|
|
4061
4066
|
end
|
|
4062
4067
|
|
|
4063
|
-
def WordAddress(wordnum); @
|
|
4068
|
+
def WordAddress(wordnum); @buffer[wordnum]; end
|
|
4064
4069
|
|
|
4065
4070
|
def WordLength(wordnum); @words[wordnum] ? @words[wordnum].length : 0; end
|
|
4066
4071
|
|
|
@@ -4196,20 +4201,20 @@ module Parser
|
|
|
4196
4201
|
i = @lightflag
|
|
4197
4202
|
@lightflag = OffersLight(parent(@player))
|
|
4198
4203
|
|
|
4199
|
-
if
|
|
4204
|
+
if i == false && @lightflag == true
|
|
4200
4205
|
@location = @real_location
|
|
4201
4206
|
log.debug "Looking after light adjustment for #{@player}" # TODO: Remove
|
|
4202
|
-
return _invoke :Look
|
|
4207
|
+
return _invoke :Look if flag == false
|
|
4203
4208
|
end
|
|
4204
4209
|
|
|
4205
|
-
if
|
|
4210
|
+
if i == true && @lightflag == false
|
|
4206
4211
|
@real_location = @location; @location = thedark
|
|
4207
|
-
|
|
4212
|
+
if flag == false
|
|
4208
4213
|
NoteArrival()
|
|
4209
4214
|
return L__M(:Miscellany, 9)
|
|
4210
4215
|
end
|
|
4211
4216
|
end
|
|
4212
|
-
@location = thedark if
|
|
4217
|
+
@location = thedark if i == false && @lightflag == false
|
|
4213
4218
|
end
|
|
4214
4219
|
|
|
4215
4220
|
def OffersLight(i)
|
|
@@ -4219,8 +4224,10 @@ module Parser
|
|
|
4219
4224
|
if i.has?(:container)
|
|
4220
4225
|
return OffersLight(parent(i)) if i.has?(:open) || i.has?(:transparent)
|
|
4221
4226
|
else
|
|
4222
|
-
return OffersLight(parent(i)) if i.has?(:enterable) ||
|
|
4227
|
+
return OffersLight(parent(i)) if i.has?(:enterable) ||
|
|
4228
|
+
i.has?(:transparent) || i.has?(:supporter)
|
|
4223
4229
|
end
|
|
4230
|
+
|
|
4224
4231
|
false
|
|
4225
4232
|
end
|
|
4226
4233
|
|
|
@@ -4271,7 +4278,7 @@ module Parser
|
|
|
4271
4278
|
i = @player; i = parent(i) until parent(i).nil?
|
|
4272
4279
|
@location = i; @real_location = @location
|
|
4273
4280
|
return RunTimeError(10) unless parent(@player)
|
|
4274
|
-
|
|
4281
|
+
MoveFloatingObjects()
|
|
4275
4282
|
@lightflag = OffersLight(parent(@player))
|
|
4276
4283
|
@location = thedark unless @lightflag
|
|
4277
4284
|
@print_player_flag = flag
|
|
@@ -4358,7 +4365,7 @@ module Parser
|
|
|
4358
4365
|
alias ShowverbSub ShowVerbSub
|
|
4359
4366
|
|
|
4360
4367
|
KnownNumberProperties = %i[number capacity time_left].freeze
|
|
4361
|
-
MethodWriterPattern = %r{=$}
|
|
4368
|
+
MethodWriterPattern = %r{=$}
|
|
4362
4369
|
|
|
4363
4370
|
def ShowobjSub
|
|
4364
4371
|
f = 0
|
|
@@ -4765,7 +4772,9 @@ module Parser
|
|
|
4765
4772
|
if defined? LanguagePrintShortName
|
|
4766
4773
|
return true if LanguagePrintShortName(o)
|
|
4767
4774
|
end # LanguagePrintShortName
|
|
4768
|
-
return true if @indef_mode &&
|
|
4775
|
+
return true if @indef_mode &&
|
|
4776
|
+
o.respond_to?(:short_name_indef) &&
|
|
4777
|
+
PrintOrRun(o, :short_name_indef, 1) != false
|
|
4769
4778
|
return true if !o.&(:short_name).nil? && PrintOrRun(o, :short_name, 1) != false
|
|
4770
4779
|
print o
|
|
4771
4780
|
end
|
|
@@ -4951,7 +4960,7 @@ module Parser
|
|
|
4951
4960
|
|
|
4952
4961
|
class NothingToRepeat < StandardError; end
|
|
4953
4962
|
|
|
4954
|
-
class
|
|
4963
|
+
class RepeatedCommand < StandardError; end
|
|
4955
4964
|
|
|
4956
4965
|
class SpeechImpediment < StandardError; end
|
|
4957
4966
|
|
|
@@ -5010,48 +5019,45 @@ class InformLibrary < Inform::Ephemeral::Object
|
|
|
5010
5019
|
def play
|
|
5011
5020
|
@real_location = thedark
|
|
5012
5021
|
@player = selfobj; @actor = @player
|
|
5013
|
-
|
|
5022
|
+
log.debug "Setting capacity of #{selfobj.identity} to #{MAX_CARRIED}"
|
|
5023
|
+
selfobj.&(:capacity, MAX_CARRIED) # ### change?
|
|
5024
|
+
log.debug " selfobj.&(:capacity): #{selfobj.&(:capacity)}"
|
|
5014
5025
|
|
|
5015
5026
|
new_line
|
|
5016
5027
|
LibraryExtensions.RunAll(:ext_initialise)
|
|
5017
5028
|
j = Initialise()
|
|
5029
|
+
# Ruby doesn't automatically print implicitly returned strings :(
|
|
5018
5030
|
println j if j.is_a?(String)
|
|
5031
|
+
@last_score = @score
|
|
5019
5032
|
move @player, @location
|
|
5020
|
-
light_adjusted @player
|
|
5021
5033
|
|
|
5022
5034
|
@location = @location.parent until @location.parent.nil?
|
|
5023
5035
|
@real_location = @location
|
|
5024
5036
|
@actor = @player # resync, because player may have been changed in initialise()
|
|
5025
5037
|
Banner() if j != 2
|
|
5038
|
+
MoveFloatingObjects()
|
|
5026
5039
|
@lightflag = OffersLight(@player.parent)
|
|
5027
5040
|
if @lightflag == false
|
|
5028
5041
|
@real_location = @location
|
|
5029
5042
|
@location = @thedark
|
|
5030
5043
|
end
|
|
5031
|
-
OBIT_HEAD() if deadflag
|
|
5032
|
-
@player.mute if deadflag
|
|
5044
|
+
OBIT_HEAD() if deadflag != 0
|
|
5033
5045
|
invoke :Look
|
|
5034
|
-
deadflag ? :death : :playing
|
|
5046
|
+
deadflag != 0 ? :death : :playing
|
|
5035
5047
|
end
|
|
5036
5048
|
|
|
5037
5049
|
def playing
|
|
5038
|
-
@player.unmute if @player.respond_to?(:unmute) &&
|
|
5050
|
+
@player.unmute if @player.respond_to?(:unmute) && deadflag != 0
|
|
5039
5051
|
enqueue(command: @buffer.dup)
|
|
5040
5052
|
|
|
5041
|
-
|
|
5042
|
-
|
|
5043
|
-
|
|
5053
|
+
if deadflag != 0
|
|
5054
|
+
log.debug "#{@player} is entering the death state" # TODO: Remove
|
|
5055
|
+
:death
|
|
5044
5056
|
end
|
|
5045
5057
|
|
|
5046
|
-
|
|
5047
|
-
return very__late__error if deadflag == 0
|
|
5058
|
+
return session.state if respond_to?(:session) && !session.nil?
|
|
5048
5059
|
|
|
5049
|
-
|
|
5050
|
-
ScoreSub()
|
|
5051
|
-
DisplayStatus()
|
|
5052
|
-
AfterGameOver()
|
|
5053
|
-
log.debug "#{@player} is entering the death state" # TODO: Remove
|
|
5054
|
-
:death
|
|
5060
|
+
__method__
|
|
5055
5061
|
end
|
|
5056
5062
|
|
|
5057
5063
|
def stop
|
|
@@ -5092,18 +5098,48 @@ class InformLibrary < Inform::Ephemeral::Object
|
|
|
5092
5098
|
|
|
5093
5099
|
@results = [nil, 0, nil, nil]; @meta = false
|
|
5094
5100
|
|
|
5095
|
-
|
|
5096
|
-
catch
|
|
5101
|
+
# i = 0
|
|
5102
|
+
# catch(:continue) do
|
|
5103
|
+
# rubocop: disable Lint/UnreachableLoop
|
|
5104
|
+
while @deadflag == 0 # everything happens in this loop
|
|
5105
|
+
return very__late__error()
|
|
5106
|
+
end
|
|
5107
|
+
# rubocop: enable Lint/UnreachableLoop
|
|
5108
|
+
# end
|
|
5109
|
+
AfterLife() if deadflag != 2
|
|
5110
|
+
return very__late__error if deadflag == 0
|
|
5111
|
+
|
|
5112
|
+
OBIT_HEAD()
|
|
5113
|
+
ScoreSub()
|
|
5114
|
+
DisplayStatus()
|
|
5115
|
+
AfterGameOver()
|
|
5116
|
+
end
|
|
5117
|
+
|
|
5118
|
+
def very__late__error
|
|
5119
|
+
if @score != @last_score
|
|
5120
|
+
NotifyTheScore() if @notify_mode == true
|
|
5121
|
+
@last_score = @score
|
|
5122
|
+
end
|
|
5123
|
+
late__error()
|
|
5124
|
+
rescue NoVerbRoutine, NotImplemented
|
|
5125
|
+
"Sorry, that action is not yet implemented."
|
|
5126
|
+
rescue NoMethodError => e
|
|
5127
|
+
parser_error e, "Sorry, there was a program error involving a missing method."
|
|
5128
|
+
rescue TypeError => e
|
|
5129
|
+
parser_error e, "Sorry, there was a program error involving the wrong type of object."
|
|
5130
|
+
rescue StandardError => e
|
|
5131
|
+
parser_error e, "Sorry, there was an unhandled program error."
|
|
5132
|
+
end
|
|
5133
|
+
|
|
5134
|
+
def late__error
|
|
5135
|
+
|
|
5097
5136
|
# The Parser writes its results into @results and @meta,
|
|
5098
5137
|
# a flag indicating a "meta-verb". This can only be set for
|
|
5099
5138
|
# commands by the player, not for orders to others.
|
|
5100
5139
|
|
|
5101
|
-
parse_input
|
|
5102
|
-
|
|
5103
|
-
return if deadflag && !@meta
|
|
5104
|
-
end
|
|
5105
|
-
# ReParse
|
|
5140
|
+
parse_input
|
|
5106
5141
|
|
|
5142
|
+
# (Port note: inputobjs is now just results.)
|
|
5107
5143
|
@action = @results[0]
|
|
5108
5144
|
|
|
5109
5145
|
# --------------------------------------------------------------
|
|
@@ -5135,119 +5171,18 @@ class InformLibrary < Inform::Ephemeral::Object
|
|
|
5135
5171
|
@multiflag = false; @onotheld_mode = @notheld_mode; @notheld_mode = false
|
|
5136
5172
|
# For implicit taking and multiple object detection
|
|
5137
5173
|
|
|
5138
|
-
|
|
5139
|
-
@inp1 = nil; @inp2 = nil; i = @results[1]
|
|
5140
|
-
@inp1 = @results[2] if i >= 1
|
|
5141
|
-
@inp2 = @results[3] if i >= 2
|
|
5142
|
-
|
|
5143
|
-
# inp1 and inp2 hold: object numbers, or 0 for "multiple object",
|
|
5144
|
-
# or 1 for "a number or dictionary address"
|
|
5145
|
-
|
|
5146
|
-
if @inp1 == 1 then @noun = @special_number1 else @noun = @inp1 end
|
|
5147
|
-
if @inp2 == 1
|
|
5148
|
-
if @inp1 == 1 then @second = @special_number2
|
|
5149
|
-
else @second = @special_number1
|
|
5150
|
-
end
|
|
5151
|
-
else @second = @inp2
|
|
5152
|
-
end
|
|
5153
|
-
|
|
5154
|
-
# --------------------------------------------------------------
|
|
5155
|
-
|
|
5156
|
-
# TODO: FIXME
|
|
5157
|
-
# act_requester = nil
|
|
5158
|
-
#
|
|
5159
|
-
# if @actor != @player
|
|
5160
|
-
#
|
|
5161
|
-
# # The player's "orders" property can refuse to allow conversation
|
|
5162
|
-
# # here, by returning true. If not, the order is sent to the
|
|
5163
|
-
# # other person's "orders" property. If that also returns false,
|
|
5164
|
-
# # then: if it was a misunderstood command anyway, it is converted
|
|
5165
|
-
# # to an Answer action (thus "floyd, grrr" ends up as
|
|
5166
|
-
# # "say grrr to floyd"). If it was a good command, it is finally
|
|
5167
|
-
# # offered to the Order: part of the other person's "life"
|
|
5168
|
-
# # property, the old-fashioned way of dealing with conversation.
|
|
5169
|
-
#
|
|
5170
|
-
# j = RunRoutines(@player, :orders)
|
|
5171
|
-
# unless j
|
|
5172
|
-
# j = RunRoutines(@actor, :orders)
|
|
5173
|
-
# unless j
|
|
5174
|
-
# if action == :NotUnderstood
|
|
5175
|
-
# @results[3] = @actor; @actor = @player; @action = :Answer
|
|
5176
|
-
# #jump begin__action
|
|
5177
|
-
# end
|
|
5178
|
-
# if RunLife(@actor, :Order) == 0; L__M(:Order, 1, @actor); end
|
|
5179
|
-
# end
|
|
5180
|
-
# end
|
|
5181
|
-
# return # jump turn__end
|
|
5182
|
-
# end
|
|
5183
|
-
|
|
5184
|
-
# --------------------------------------------------------------
|
|
5185
|
-
# Generate the action...
|
|
5186
|
-
|
|
5187
|
-
if (i == 0) ||
|
|
5188
|
-
(i == 1 && @inp1 != 0) ||
|
|
5189
|
-
(i == 2 && @inp1 != 0 && @inp2 != 0) ||
|
|
5190
|
-
(i == @parameters && @inp1 != 0 && @inp2 != 0)
|
|
5191
|
-
result = self.begin_action(@action, @noun, @second, 0)
|
|
5192
|
-
# jump turn__end
|
|
5193
|
-
else
|
|
5194
|
-
|
|
5195
|
-
# ...unless a multiple object must be substituted. First:
|
|
5196
|
-
# (a) check the multiple list isn't empty;
|
|
5197
|
-
# (b) warn the player if it has been cut short because too long;
|
|
5198
|
-
# (c) generate a sequence of actions from the list
|
|
5199
|
-
# (stopping in the event of death or movement away).
|
|
5200
|
-
|
|
5201
|
-
@multiflag = true
|
|
5202
|
-
if @multiple_object.empty?
|
|
5203
|
-
return L__M(:Miscellany, 2)
|
|
5204
|
-
# jump late__error
|
|
5205
|
-
end
|
|
5206
|
-
if @toomany_flag
|
|
5207
|
-
@toomany_flag = false
|
|
5208
|
-
print L__M(:Miscellany, 1)
|
|
5209
|
-
end
|
|
5210
|
-
i = @location
|
|
5211
|
-
for l in @multiple_object
|
|
5212
|
-
return if deadflag
|
|
5213
|
-
return L__M(:Miscellany, 51) if @location != i
|
|
5214
|
-
PronounNotice(l)
|
|
5215
|
-
@second = @results[3]
|
|
5216
|
-
print "#{l}: "
|
|
5217
|
-
if @inp1 == 0
|
|
5218
|
-
@inp1 = l; zmsnp self.begin_action(@action, l, @second, 0); @inp1 = 0
|
|
5219
|
-
else
|
|
5220
|
-
@inp2 = l; zmsnp self.begin_action(@action, @noun, l, 0); @inp2 = 0
|
|
5221
|
-
end
|
|
5222
|
-
end
|
|
5223
|
-
end
|
|
5224
|
-
|
|
5225
|
-
# --------------------------------------------------------------
|
|
5226
|
-
|
|
5227
|
-
# label :turn__end do
|
|
5174
|
+
begin__action()
|
|
5228
5175
|
|
|
5229
|
-
|
|
5230
|
-
|
|
5231
|
-
|
|
5232
|
-
|
|
5233
|
-
NoteObjectAcquisitions()
|
|
5234
|
-
println(result, should_prompt: false)
|
|
5235
|
-
return true if result == false
|
|
5236
|
-
next
|
|
5237
|
-
end
|
|
5238
|
-
return result if @meta
|
|
5239
|
-
if defined? SINGLE_PLAYER
|
|
5240
|
-
self.end_turn_sequence() unless deadflag
|
|
5241
|
-
end
|
|
5242
|
-
println(result) if result.is_a?(String)
|
|
5243
|
-
# return result if defined? result
|
|
5244
|
-
return true
|
|
5245
|
-
end
|
|
5246
|
-
# 2.times do # NotHeld
|
|
5247
|
-
rescue RepeatedOrder
|
|
5248
|
-
return L__M(:Miscellany, REPEATED_ORDER)
|
|
5176
|
+
return session.state if respond_to?(:session) && !session.nil?
|
|
5177
|
+
true
|
|
5178
|
+
rescue RepeatedCommand
|
|
5179
|
+
return L__M(:Miscellany, REPEATED_COMMAND)
|
|
5249
5180
|
rescue NothingToRepeat
|
|
5250
5181
|
return L__M(:Miscellany, NOTHING_TO_REPEAT)
|
|
5182
|
+
rescue UnexpectedComma
|
|
5183
|
+
return L__M(:Miscellany, UNEXPECTED_COMMA)
|
|
5184
|
+
rescue MissingAddressee
|
|
5185
|
+
return L__M(:Miscellany, MISSING_ADDRESSEE)
|
|
5251
5186
|
rescue InanimateAddressee
|
|
5252
5187
|
return L__M(:Miscellany, CANT_TALK, noun)
|
|
5253
5188
|
rescue SpeechImpediment
|
|
@@ -5325,46 +5260,125 @@ class InformLibrary < Inform::Ephemeral::Object
|
|
|
5325
5260
|
return L__M(:Miscellany, NO_OBJECT)
|
|
5326
5261
|
rescue CycleError
|
|
5327
5262
|
return L__M(:Miscellany, TREE_ERROR)
|
|
5328
|
-
rescue NoVerbRoutine, NotImplemented
|
|
5329
|
-
return "Sorry, that action is not yet implemented."
|
|
5330
|
-
rescue NoMethodError => e
|
|
5331
|
-
log.error "Error parsing user command: #{e.class}: #{e}"
|
|
5332
|
-
e.backtrace.each { |t| log.error t }
|
|
5333
|
-
log.error "Parser was #{self.identity}"
|
|
5334
|
-
log.error "Input was: #{@input}"
|
|
5335
|
-
log.error "Actor was: #{@actor}"
|
|
5336
|
-
log.error "Action was: #{@action}"
|
|
5337
|
-
return "Sorry, something went wrong."
|
|
5338
|
-
rescue TypeError => e
|
|
5339
|
-
log.error "Error parsing user command: #{e.class}: #{e}"
|
|
5340
|
-
e.backtrace.each { |t| log.error t }
|
|
5341
|
-
log.error "Parser was #{self.identity}"
|
|
5342
|
-
log.error "Input was: #{@input}"
|
|
5343
|
-
log.error "Actor was: #{@actor}"
|
|
5344
|
-
log.error "Action was: #{@action}"
|
|
5345
|
-
return "Sorry, something went wrong."
|
|
5346
|
-
rescue StandardError => e
|
|
5347
|
-
log.error "Error parsing user command: #{e.class}: #{e}"
|
|
5348
|
-
e.backtrace.each { |t| log.error t }
|
|
5349
|
-
log.error "Parser was #{self.identity}"
|
|
5350
|
-
log.error "Input was: #{@input}"
|
|
5351
|
-
log.error "Actor was: #{@actor}"
|
|
5352
|
-
log.error "Action was: #{@action}"
|
|
5353
|
-
return "Sorry, something went seriously wrong."
|
|
5354
5263
|
end
|
|
5355
|
-
# def
|
|
5264
|
+
# def late__error
|
|
5265
|
+
|
|
5266
|
+
def begin__action()
|
|
5267
|
+
@inp1 = nil; @inp2 = nil; i = @results[1]
|
|
5268
|
+
@inp1 = @results[2] if i >= 1
|
|
5269
|
+
@inp2 = @results[3] if i >= 2
|
|
5270
|
+
|
|
5271
|
+
# inp1 and inp2 hold: object numbers, or 0 for "multiple object",
|
|
5272
|
+
# or 1 for "a number or dictionary address"
|
|
5273
|
+
|
|
5274
|
+
if @inp1 == 1 then @noun = @special_number1 else @noun = @inp1 end
|
|
5275
|
+
if @inp2 == 1
|
|
5276
|
+
if @inp1 == 1 then @second = @special_number2
|
|
5277
|
+
else @second = @special_number1
|
|
5278
|
+
end
|
|
5279
|
+
else @second = @inp2
|
|
5280
|
+
end
|
|
5281
|
+
|
|
5282
|
+
# --------------------------------------------------------------
|
|
5283
|
+
|
|
5284
|
+
if @actor != @player
|
|
5285
|
+
|
|
5286
|
+
# The player's "orders" property can refuse to allow conversation
|
|
5287
|
+
# here, by returning true. If not, the order is sent to the
|
|
5288
|
+
# other person's "orders" property. If that also returns false,
|
|
5289
|
+
# then: if it was a misunderstood command anyway, it is converted
|
|
5290
|
+
# to an Answer action (thus "floyd, grrr" ends up as
|
|
5291
|
+
# "say grrr to floyd"). If it was a good command, it is finally
|
|
5292
|
+
# offered to the Order: part of the other person's "life"
|
|
5293
|
+
# property, the old-fashioned way of dealing with conversation.
|
|
5294
|
+
|
|
5295
|
+
j = RunRoutines(@player, :orders)
|
|
5296
|
+
if j == false || j.nil?
|
|
5297
|
+
j = RunRoutines(@actor, :orders)
|
|
5298
|
+
if j == false || j.nil?
|
|
5299
|
+
if @action == :NotUnderstood
|
|
5300
|
+
@results[3] = @actor; @actor = @player; @action = :Answer
|
|
5301
|
+
return begin__action()
|
|
5302
|
+
end
|
|
5303
|
+
if RunLife(@actor, :Order) == 0 then L__M(:Order, 1, @actor); end
|
|
5304
|
+
end
|
|
5305
|
+
end
|
|
5306
|
+
return turn__end()
|
|
5307
|
+
end
|
|
5308
|
+
|
|
5309
|
+
# --------------------------------------------------------------
|
|
5310
|
+
# Generate the action...
|
|
5311
|
+
|
|
5312
|
+
if (i == 0) ||
|
|
5313
|
+
(i == 1 && @inp1 != 0) ||
|
|
5314
|
+
(i == 2 && @inp1 != 0 && @inp2 != 0) ||
|
|
5315
|
+
(i == @parameters && @inp1 != 0 && @inp2 != 0)
|
|
5316
|
+
result = self.begin_action(@action, @noun, @second, 0)
|
|
5317
|
+
print_routine_result(result)
|
|
5318
|
+
return turn__end(result)
|
|
5319
|
+
end
|
|
5320
|
+
|
|
5321
|
+
# ...unless a multiple object must be substituted. First:
|
|
5322
|
+
# (a) check the multiple list isn't empty;
|
|
5323
|
+
# (b) warn the player if it has been cut short because too long;
|
|
5324
|
+
# (c) generate a sequence of actions from the list
|
|
5325
|
+
# (stopping in the event of death or movement away).
|
|
5326
|
+
|
|
5327
|
+
@multiflag = true
|
|
5328
|
+
if @multiple_object.empty?
|
|
5329
|
+
return L__M(:Miscellany, 2)
|
|
5330
|
+
return late__error() # rubocop: disable Lint/UnreachableCode
|
|
5331
|
+
end
|
|
5332
|
+
if @toomany_flag
|
|
5333
|
+
@toomany_flag = false
|
|
5334
|
+
print L__M(:Miscellany, 1)
|
|
5335
|
+
end
|
|
5336
|
+
i = @location
|
|
5337
|
+
for l in @multiple_object
|
|
5338
|
+
return if deadflag != 0
|
|
5339
|
+
return L__M(:Miscellany, 51) if @location != i
|
|
5340
|
+
PronounNotice(l)
|
|
5341
|
+
@second = @results[3]
|
|
5342
|
+
print "#{l}: "
|
|
5343
|
+
if @inp1.nil?
|
|
5344
|
+
@inp1 = l; result = self.begin_action(@action, l, @second, 0); @inp1 = nil
|
|
5345
|
+
else
|
|
5346
|
+
@inp2 = l; result = self.begin_action(@action, @noun, l, 0); @inp2 = nil
|
|
5347
|
+
end
|
|
5348
|
+
print_routine_result(result)
|
|
5349
|
+
end
|
|
5350
|
+
turn__end(result)
|
|
5351
|
+
end
|
|
5352
|
+
# def begin__action
|
|
5353
|
+
|
|
5354
|
+
# --------------------------------------------------------------
|
|
5355
|
+
|
|
5356
|
+
def turn__end(result = nil)
|
|
5357
|
+
|
|
5358
|
+
# No time passes if either (i) the verb was meta, or
|
|
5359
|
+
# (ii) we've only had the implicit take before the "real"
|
|
5360
|
+
# action to follow.
|
|
5361
|
+
# if @notheld_mode then NoteObjectAcquisitions(); throw :continue; end
|
|
5362
|
+
if @notheld_mode then NoteObjectAcquisitions(); return true; end
|
|
5363
|
+
# throw :continue if @meta
|
|
5364
|
+
return true if @meta
|
|
5365
|
+
unless defined?(MULTI_PLAYER)
|
|
5366
|
+
self.end_turn_sequence() if deadflag == 0
|
|
5367
|
+
end
|
|
5368
|
+
result
|
|
5369
|
+
end
|
|
5356
5370
|
|
|
5357
5371
|
def end_turn_sequence
|
|
5358
5372
|
AdvanceWorldClock()
|
|
5359
|
-
return if deadflag
|
|
5373
|
+
return if deadflag != 0
|
|
5360
5374
|
RunTimersAndDaemons()
|
|
5361
|
-
return if deadflag
|
|
5375
|
+
return if deadflag != 0
|
|
5362
5376
|
RunEachTurnProperties()
|
|
5363
|
-
return if deadflag
|
|
5377
|
+
return if deadflag != 0
|
|
5364
5378
|
TimePasses()
|
|
5365
|
-
return if deadflag
|
|
5379
|
+
return if deadflag != 0
|
|
5366
5380
|
AdjustLight()
|
|
5367
|
-
return if deadflag
|
|
5381
|
+
return if deadflag != 0
|
|
5368
5382
|
NoteObjectAcquisitions()
|
|
5369
5383
|
end
|
|
5370
5384
|
|
|
@@ -5381,7 +5395,8 @@ class InformLibrary < Inform::Ephemeral::Object
|
|
|
5381
5395
|
end # DEBUG
|
|
5382
5396
|
|
|
5383
5397
|
contextualize
|
|
5384
|
-
|
|
5398
|
+
before = BeforeRoutines(a)
|
|
5399
|
+
if (!@verb.nil? && @verb.meta?) || before == false
|
|
5385
5400
|
rv = ActionPrimitive(a)
|
|
5386
5401
|
end
|
|
5387
5402
|
return rv
|
|
@@ -5395,9 +5410,9 @@ class InformLibrary < Inform::Ephemeral::Object
|
|
|
5395
5410
|
color :black_on_white
|
|
5396
5411
|
bgcolor :white
|
|
5397
5412
|
print "***"
|
|
5398
|
-
L__M(:Miscellany, 3) if deadflag
|
|
5413
|
+
L__M(:Miscellany, 3) if deadflag != 0
|
|
5399
5414
|
L__M(:Miscellany, 4) if deadflag == 2
|
|
5400
|
-
if deadflag !=
|
|
5415
|
+
if deadflag != 0 && deadflag != 1 && deadflag != 2
|
|
5401
5416
|
print " "
|
|
5402
5417
|
DeathMessage()
|
|
5403
5418
|
print " "
|
|
@@ -5415,7 +5430,7 @@ class InformLibrary < Inform::Ephemeral::Object
|
|
|
5415
5430
|
end
|
|
5416
5431
|
|
|
5417
5432
|
def AdvanceWorldClock
|
|
5418
|
-
return
|
|
5433
|
+
return if defined?(MULTI_PLAYER)
|
|
5419
5434
|
@turns += 1
|
|
5420
5435
|
if !@the_time.nil?
|
|
5421
5436
|
if @time_rate >= 0 then @the_time = @the_time + @time_rate
|
|
@@ -5431,10 +5446,10 @@ class InformLibrary < Inform::Ephemeral::Object
|
|
|
5431
5446
|
end
|
|
5432
5447
|
|
|
5433
5448
|
def RunTimersAndDaemons
|
|
5434
|
-
return if
|
|
5449
|
+
return if defined?(MULTI_PLAYER)
|
|
5435
5450
|
if defined?(DEBUG)
|
|
5436
5451
|
if (@debug_flag & 4) != 0
|
|
5437
|
-
@
|
|
5452
|
+
@the_timers.each do |the_timer|
|
|
5438
5453
|
next if the_timer.nil?
|
|
5439
5454
|
print name(the_timer & !WORD_HIGHBIT) + ": "
|
|
5440
5455
|
if (the_timer & WORD_HIGHBIT) != 0 then print "daemon"
|
|
@@ -5446,21 +5461,21 @@ class InformLibrary < Inform::Ephemeral::Object
|
|
|
5446
5461
|
end
|
|
5447
5462
|
end # DEBUG
|
|
5448
5463
|
|
|
5449
|
-
@
|
|
5464
|
+
@the_timers.each do |the_timer|
|
|
5450
5465
|
break if deadflag != 0
|
|
5451
5466
|
next if the_timer.nil?
|
|
5452
|
-
if (
|
|
5453
|
-
elsif the_timer
|
|
5467
|
+
if the_timer.respond_to?(:daemon) then RunRoutines(the_timer, :daemon)
|
|
5468
|
+
elsif (the_timer.&(:time_left) || nil) == 0
|
|
5454
5469
|
StopTimer(the_timer)
|
|
5455
|
-
RunRoutines(the_timer, time_out)
|
|
5470
|
+
RunRoutines(the_timer, :time_out)
|
|
5456
5471
|
else
|
|
5457
|
-
the_timer
|
|
5472
|
+
the_timer.&(:time_left, the_timer.|(:time_left, 0) - 1)
|
|
5458
5473
|
end
|
|
5459
5474
|
end
|
|
5460
5475
|
end
|
|
5461
5476
|
|
|
5462
5477
|
def RunEachTurnProperties
|
|
5463
|
-
return
|
|
5478
|
+
return if defined?(MULTI_PLAYER)
|
|
5464
5479
|
@scope_reason = scope_reason = EACH_TURN_REASON; @verb_word = nil
|
|
5465
5480
|
DoScopeAction(@location, scope_reason)
|
|
5466
5481
|
SearchScope(ScopeCeiling(@player), @player, nil)
|
|
@@ -5477,7 +5492,7 @@ class InformLibrary < Inform::Ephemeral::Object
|
|
|
5477
5492
|
end
|
|
5478
5493
|
|
|
5479
5494
|
def AfterGameOver
|
|
5480
|
-
return
|
|
5495
|
+
return if defined?(MULTI_PLAYER)
|
|
5481
5496
|
prompt
|
|
5482
5497
|
@temp_global = 0
|
|
5483
5498
|
i = @parse[1]
|
|
@@ -5506,13 +5521,15 @@ class InformLibrary < Inform::Ephemeral::Object
|
|
|
5506
5521
|
|
|
5507
5522
|
def R_Process(a, i, j)
|
|
5508
5523
|
s1 = @inp1; s2 = @inp2
|
|
5509
|
-
@inp1 = i; @inp2 = j;
|
|
5524
|
+
@inp1 = i; @inp2 = j; result = self.begin_action(a, i, j, 1)
|
|
5525
|
+
print_routine_result(result)
|
|
5526
|
+
ensure
|
|
5510
5527
|
@inp1 = s1; @inp2 = s2
|
|
5511
5528
|
end
|
|
5512
5529
|
|
|
5513
5530
|
def NoteObjectAcquisitions
|
|
5514
|
-
return
|
|
5515
|
-
player.objectloop
|
|
5531
|
+
return if defined?(MULTI_PLAYER)
|
|
5532
|
+
player.objectloop do |i|
|
|
5516
5533
|
if i.hasnt?(:moved)
|
|
5517
5534
|
give i, :moved
|
|
5518
5535
|
if i.has?(:scored)
|
|
@@ -5581,24 +5598,27 @@ class InformLibrary < Inform::Ephemeral::Object
|
|
|
5581
5598
|
|
|
5582
5599
|
def ZRegion(z)
|
|
5583
5600
|
return 0 if z.nil?
|
|
5584
|
-
|
|
5601
|
+
return 1 if z.object?
|
|
5602
|
+
case z # Left over from Inform 5
|
|
5585
5603
|
# when NilClass then 0
|
|
5586
|
-
when
|
|
5604
|
+
when Class then 1
|
|
5587
5605
|
when Symbol then 2
|
|
5588
5606
|
when String then 3
|
|
5589
5607
|
end
|
|
5590
5608
|
end
|
|
5591
5609
|
|
|
5592
|
-
def PrintOrRun(obj, prop, flag =
|
|
5610
|
+
def PrintOrRun(obj, prop, flag = false)
|
|
5593
5611
|
si = obj.inflib; obj.inflib = inflib
|
|
5594
|
-
return RunRoutines(obj, prop) if obj.properties.include?(prop)
|
|
5612
|
+
# return RunRoutines(obj, prop) if obj.properties.include?(prop)
|
|
5613
|
+
return RunRoutines(obj, prop) if obj.properties[prop].is_a?(Array)
|
|
5595
5614
|
if obj.respond_to?(prop) && !obj.method(prop).nil?
|
|
5596
5615
|
result = obj.send(prop)
|
|
5597
5616
|
if result.is_a?(Class) || result.nil? || obj.linked?(prop)
|
|
5598
5617
|
return RunTimeError(2, obj, prop)
|
|
5599
5618
|
elsif result.is_a?(String)
|
|
5600
5619
|
print result.to_s
|
|
5601
|
-
|
|
5620
|
+
raise "Why is flag true?" if flag == true
|
|
5621
|
+
new_line if flag == false
|
|
5602
5622
|
return true
|
|
5603
5623
|
else
|
|
5604
5624
|
return result
|
|
@@ -5610,12 +5630,12 @@ class InformLibrary < Inform::Ephemeral::Object
|
|
|
5610
5630
|
obj.inflib = si
|
|
5611
5631
|
end
|
|
5612
5632
|
|
|
5613
|
-
def PrintOrRunVar(var, flag)
|
|
5633
|
+
def PrintOrRunVar(var, flag = false)
|
|
5614
5634
|
if var.respond_to?(:name)
|
|
5615
5635
|
print var.name
|
|
5616
5636
|
elsif var.is_a?(String)
|
|
5617
5637
|
print var
|
|
5618
|
-
new_line if flag ==
|
|
5638
|
+
new_line if flag == false
|
|
5619
5639
|
elsif var.respond_to?(:call)
|
|
5620
5640
|
return var.call
|
|
5621
5641
|
else
|
|
@@ -5625,15 +5645,77 @@ class InformLibrary < Inform::Ephemeral::Object
|
|
|
5625
5645
|
end
|
|
5626
5646
|
|
|
5627
5647
|
def ValueOrRun(obj, prop)
|
|
5628
|
-
|
|
5629
|
-
|
|
5648
|
+
if obj.properties.key?(prop)
|
|
5649
|
+
value = obj.&(prop)
|
|
5650
|
+
return value.number? ? value.to_i : value
|
|
5651
|
+
elsif obj.respond_to?(prop)
|
|
5652
|
+
value = obj.send(prop)
|
|
5653
|
+
return value.number? ? value.to_i : value
|
|
5654
|
+
end
|
|
5655
|
+
return RunRoutines(obj, prop)
|
|
5630
5656
|
end
|
|
5631
5657
|
|
|
5632
5658
|
def RunRoutines(obj, prop)
|
|
5633
5659
|
obj = @real_location if obj == thedark && prop.notin?(:initial, :short_name, :description, :life)
|
|
5634
5660
|
return false if prop.nil?
|
|
5635
|
-
|
|
5636
|
-
|
|
5661
|
+
|
|
5662
|
+
value = obj.&(prop)
|
|
5663
|
+
return print_routine_result(value) unless value.nil?
|
|
5664
|
+
|
|
5665
|
+
reacts_to?(obj, prop)
|
|
5666
|
+
end
|
|
5667
|
+
|
|
5668
|
+
# ----------------------------------------------------------------------------
|
|
5669
|
+
|
|
5670
|
+
def StartTimer(obj, timer)
|
|
5671
|
+
return false if @the_timers.include?(obj)
|
|
5672
|
+
if @the_timers.length >= MAX_TIMERS
|
|
5673
|
+
RunTimeError(4)
|
|
5674
|
+
return
|
|
5675
|
+
end
|
|
5676
|
+
if obj.&(:time_left) == 0
|
|
5677
|
+
RunTimeError(5,obj)
|
|
5678
|
+
return
|
|
5679
|
+
end
|
|
5680
|
+
@the_timers << obj
|
|
5681
|
+
obj.&(:time_left, timer)
|
|
5682
|
+
end
|
|
5683
|
+
|
|
5684
|
+
def StopTimer(obj)
|
|
5685
|
+
return false unless @the_timers.include?(obj)
|
|
5686
|
+
if obj.&(:time_left) == 0
|
|
5687
|
+
RunTimeError(5,obj)
|
|
5688
|
+
return
|
|
5689
|
+
end
|
|
5690
|
+
@the_timers.delete(obj)
|
|
5691
|
+
obj.&(:time_left, 0)
|
|
5692
|
+
end
|
|
5693
|
+
|
|
5694
|
+
def StartDaemon(obj)
|
|
5695
|
+
return false if @the_timers.include?(obj)
|
|
5696
|
+
RunTimeError(4) if @the_timers.length >= MAX_TIMERS
|
|
5697
|
+
@the_timers << obj
|
|
5698
|
+
end
|
|
5699
|
+
|
|
5700
|
+
def StopDaemon(obj)
|
|
5701
|
+
return false unless @the_timers.include?(obj)
|
|
5702
|
+
@the_timers.delete(obj)
|
|
5703
|
+
end
|
|
5704
|
+
|
|
5705
|
+
# ----------------------------------------------------------------------------
|
|
5706
|
+
|
|
5707
|
+
def DisplayStatus
|
|
5708
|
+
if @sys_statusline_flag == 0 then @sline1 = @score; @sline2 = @turns
|
|
5709
|
+
else @sline1 = @the_time/60; @sline2 = @the_time%60; end
|
|
5710
|
+
end
|
|
5711
|
+
|
|
5712
|
+
def SetTime(t, s)
|
|
5713
|
+
@the_time = t; @time_rate = s; @time_step = 0
|
|
5714
|
+
@time_step = 0 - s if s < 0
|
|
5715
|
+
end
|
|
5716
|
+
|
|
5717
|
+
def NotifyTheScore
|
|
5718
|
+
print "\n["; L__M(:Miscellany, 50, @score - @last_score); print ".]\n"
|
|
5637
5719
|
end
|
|
5638
5720
|
# ----------------------------------------------------------------------------
|
|
5639
5721
|
end
|