Обновление библиотеки метапарсера
This commit is contained in:
parent
ccfed96788
commit
d8e4d36a66
|
@ -338,6 +338,7 @@ local function gram_score(an, g)
|
|||
g = gram_norm(g)
|
||||
if an["фам"] then score = score - 0.1 end
|
||||
if an["арх"] then score = score - 0.1 end
|
||||
if not g["од"] and not g["но"] and an["од"] and not an["но"] then score = score - 0.1 end
|
||||
for _, vv in ipairs(g or {}) do
|
||||
if vv:sub(1, 1) == '~' then
|
||||
vv = vv:sub(2)
|
||||
|
@ -400,6 +401,14 @@ lang = { yo = false,
|
|||
"деревьях/пр";
|
||||
"деревьям/дт";
|
||||
};
|
||||
["листья/мр,но,мн,С"] = {
|
||||
"листья/им";
|
||||
"листья/вн";
|
||||
"листьев/рд";
|
||||
"листьями/тв";
|
||||
"листьях/пр";
|
||||
"листьям/дт";
|
||||
};
|
||||
["дерево/ср,но,С"] = {
|
||||
"дерево/им", "деревья/им,мн";
|
||||
"дерево/вн", "деревья/вн,мн";
|
||||
|
|
|
@ -605,9 +605,9 @@ end
|
|||
function mrd:dict(dict, word)
|
||||
if not dict then return end
|
||||
local tab = {}
|
||||
local w, hints = str_hint(word)
|
||||
local wrd, hints = str_hint(word)
|
||||
hints = str_split(hints, ",")
|
||||
local tt = dict[w]
|
||||
local tt = dict[wrd]
|
||||
|
||||
if not tt then
|
||||
return
|
||||
|
|
189
parser/mp-en.lua
189
parser/mp-en.lua
|
@ -70,7 +70,8 @@ mp.shorten = {
|
|||
["se"] = "southeast";
|
||||
["sw"] = "southwest";
|
||||
["nw"] = "northwest";
|
||||
|
||||
["u"] = "up";
|
||||
["d"] = "down";
|
||||
}
|
||||
|
||||
mp.shorten_expert = {
|
||||
|
@ -87,8 +88,13 @@ function mp:skip_filter(w)
|
|||
end
|
||||
return true
|
||||
end
|
||||
|
||||
_'@compass'.before_Default = 'Try to verb "go".'
|
||||
function mp:ignore_filter(w)
|
||||
if w == 'the' or w == 'a' or w == 'an' then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
_'@compass'.before_Default = function() p('"{#First}" is the direction. You can not ', mp.parsed[1], ' {#firstit}.') end
|
||||
|
||||
function mp.msg.SCORE(d)
|
||||
if d > 0 then
|
||||
|
@ -97,9 +103,17 @@ function mp.msg.SCORE(d)
|
|||
pn ("{$fmt em|(Score is decreased by ", d, ")}")
|
||||
end
|
||||
end
|
||||
|
||||
mp.door.word = "door"
|
||||
mp.msg.TITLE_SCORE = "Score: "
|
||||
mp.msg.TITLE_TURNS = "Turns: "
|
||||
mp.msg.TITLE_SCORE = function()
|
||||
if mp.maxscore then
|
||||
pr ("Score: ", mp.score, "/", mp.maxscore)
|
||||
end
|
||||
pr ("Score: ", mp.score)
|
||||
end
|
||||
mp.msg.TITLE_TURNS = function()
|
||||
pr ("Turns: ", game:time() - 1)
|
||||
end
|
||||
mp.msg.YES = "Yes"
|
||||
mp.msg.WHEN_DARK = "Darkness."
|
||||
mp.msg.UNKNOWN_THEDARK = "Probably, it is because there is no light?"
|
||||
|
@ -110,20 +124,20 @@ mp.msg.CUTSCENE_HELP = "Press <Enter> or enter {$fmt em|next} to continue."
|
|||
mp.msg.DLG_HELP = "Enter number to select the phrase."
|
||||
mp.msg.NO_ALL = "This verb can not be used with all."
|
||||
mp.msg.DROPPING_ALL = function(w)
|
||||
pn (iface:em("(dropping "..w:noun'вн'..")"))
|
||||
pn (iface:em("(dropping "..w:the_noun()..")"))
|
||||
end
|
||||
mp.msg.TAKING_ALL = function(w)
|
||||
pn (iface:em("(taking "..w:noun'вн'..")"))
|
||||
pn (iface:em("(taking "..w:the_noun()..")"))
|
||||
end
|
||||
mp.msg.TAKE_BEFORE = function(w)
|
||||
pn (iface:em("(taking "..w:the_noun().." before)"))
|
||||
pn (iface:em("(taking "..w:the_noun().." first)"))
|
||||
end
|
||||
mp.msg.DISROBE_BEFORE = function(w)
|
||||
pn (iface:em("(disrobing "..w:the_noun().." before)"))
|
||||
pn (iface:em("(disrobing "..w:the_noun().." first)"))
|
||||
end
|
||||
|
||||
mp.msg.CLOSE_BEFORE = function(w)
|
||||
pn (iface:em("(closing "..w:the_noun() .. " before)"))
|
||||
pn (iface:em("(closing "..w:the_noun() .. " first)"))
|
||||
end
|
||||
|
||||
local function str_split(str, delim)
|
||||
|
@ -136,7 +150,7 @@ end
|
|||
|
||||
function mp.shortcut.thenoun(hint)
|
||||
local w = str_split(hint, ",")
|
||||
if #w ~= 2 then
|
||||
if #w ~= 1 then
|
||||
return ""
|
||||
end
|
||||
local ob = mp:shortcut_obj(w[1])
|
||||
|
@ -329,10 +343,23 @@ end
|
|||
|
||||
mp.msg.enter = "<Enter>"
|
||||
mp.msg.EMPTY = 'Excuse me?'
|
||||
mp.msg.UNKNOWN_VERB = "Unknown verb"
|
||||
mp.msg.UNKNOWN_VERB_HINT = "Maybe you meant"
|
||||
mp.msg.UNKNOWN_VERB = function(w)
|
||||
p ("Unknown verb ", iface:em(w), ".")
|
||||
end
|
||||
mp.msg.UNKNOWN_VERB_HINT = function(w)
|
||||
p ("The most similar word is ", iface:em(w), ".")
|
||||
end
|
||||
mp.msg.INCOMPLETE = "The sentence must be supplemented."
|
||||
mp.msg.INCOMPLETE_NOUN = "What do you want to apply the command to"
|
||||
mp.msg.INCOMPLETE_NOUN = function(w)
|
||||
if w then
|
||||
p ('What do you want to apply the command "'..w..'" to?')
|
||||
else
|
||||
p "What do you want to apply the command to?"
|
||||
end
|
||||
end
|
||||
mp.msg.INCOMPLETE_SECOND_NOUN = function(w)
|
||||
p ('Clarify the command: "', w, '"?')
|
||||
end
|
||||
mp.msg.UNKNOWN_OBJ = "Here is no such thing"
|
||||
mp.msg.UNKNOWN_OBJ = function(w)
|
||||
if not w then
|
||||
|
@ -352,10 +379,9 @@ mp.msg.UNKNOWN_WORD = function(w)
|
|||
end
|
||||
mp.msg.NOTHING_OBJ = "Nothing."
|
||||
mp.msg.HINT_WORDS = "Maybe you meant"
|
||||
mp.msg.HINT_OR = "or"
|
||||
mp.msg.HINT_AND = "and"
|
||||
mp.msg.AND = "and"
|
||||
mp.msg.MULTIPLE = "Here are"
|
||||
mp.msg.OR = "or"
|
||||
mp.msg.MULTIPLE = "Here is"
|
||||
mp.msg.LIVE_ACTION = function(w)
|
||||
p (mp:It(w), " would not like it.")
|
||||
end
|
||||
|
@ -363,11 +389,17 @@ mp.msg.NO_LIVE_ACTION = "{#Me} can only do that to something animate."
|
|||
mp.msg.NOTINV = function(t)
|
||||
p (lang.cap(t:the_noun()) .. " must be taken first.")
|
||||
end
|
||||
mp.msg.WORN = function(_)
|
||||
pr (" (worn)")
|
||||
mp.msg.HAS_WORN = function(_)
|
||||
return "worn"
|
||||
end
|
||||
mp.msg.OPEN = function(_)
|
||||
pr (" (opened)")
|
||||
mp.msg.HAS_OPEN = function(_)
|
||||
return "opened"
|
||||
end
|
||||
mp.msg.HAS_ON = function(_)
|
||||
return "switched on"
|
||||
end
|
||||
mp.msg.HAS_LIGHT = function(_)
|
||||
return "providing light"
|
||||
end
|
||||
|
||||
mp.msg.EXITBEFORE = "May be, {#me} should to {#if_has/#where,supporter,get off,get out of} {#thenoun/#where}."
|
||||
|
@ -379,7 +411,7 @@ mp.msg.ACCESS1 = "{#Thefirst} {#is/#first} not accessible from here."
|
|||
mp.msg.ACCESS2 = "{#Thesecond} {#is/#second} not accessible from here."
|
||||
|
||||
mp.msg.Look.HEREIS = "Here is"
|
||||
mp.msg.Look.HEREARE = "Here are"
|
||||
mp.msg.Look.HEREARE = "Here is"
|
||||
|
||||
mp.msg.NOROOM = function(w)
|
||||
if w == std.me() then
|
||||
|
@ -392,12 +424,34 @@ mp.msg.NOROOM = function(w)
|
|||
end
|
||||
|
||||
mp.msg.Exam.SWITCHSTATE = "{#Thefirst} {#is/#first} switched {#if_has/#first,on,on,off}."
|
||||
mp.msg.Exam.NOTHING = "nothing."
|
||||
mp.msg.Exam.IS = "there is"
|
||||
mp.msg.Exam.ARE = "there are"
|
||||
mp.msg.Exam.IN = "In {#thefirst}"
|
||||
mp.msg.Exam.ON = "On {#thefirst}"
|
||||
|
||||
mp.msg.Exam.NOTHING = function(w)
|
||||
p "There is nothing "
|
||||
if w:has 'supporter' then
|
||||
mp:pnoun (w, "on {#thefirst}.")
|
||||
else
|
||||
mp:pnoun (w, "in {#thefirst}.")
|
||||
end
|
||||
end
|
||||
mp.msg.Exam.CONTENT = function(w, oo)
|
||||
local single = not oo[1]:hint 'plural'
|
||||
if std.me():where() == w or std.here() == w then
|
||||
p "{#Me} can see"
|
||||
mp:multidsc(oo)
|
||||
p " here."
|
||||
return
|
||||
end
|
||||
if single then
|
||||
p "There is"
|
||||
else
|
||||
p "There are"
|
||||
end
|
||||
mp:multidsc(oo)
|
||||
if w:has 'supporter' then
|
||||
mp:pnoun (w, " on {#thefirst}.")
|
||||
else
|
||||
mp:pnoun (w, " in {#thefirst}.")
|
||||
end
|
||||
end
|
||||
mp.msg.Exam.DEFAULT = "{#Me} {#does/#me} not see anything unusual in {#thefirst}.";
|
||||
mp.msg.Exam.SELF = "{#Me} {#does/#me} not see anything unusual in {#yourself/#me}.";
|
||||
|
||||
|
@ -409,7 +463,7 @@ mp.msg.Enter.ALREADY = "{#Me} {#is/#me} already {#if_has/#first,supporter,on,in}
|
|||
mp.msg.Enter.INV = "{#Me} {#is/#me} unable to enter the thing {#me} {#is/#me} holding."
|
||||
mp.msg.Enter.IMPOSSIBLE = "But {#me} {#is/#me} unable to enter in/on {#thefirst}."
|
||||
mp.msg.Enter.CLOSED = "{#Thefirst} {#is/#first} closed and {#me} can't enter there."
|
||||
mp.msg.Enter.ENTERED = "{#Me} {#word/залезать,нст,#me} {#if_has/#first,supporter,на,в} {#first/вн}."
|
||||
mp.msg.Enter.ENTERED = "{#Me} {#present/#me,get} {#if_has/#first,supporter,on,into} {#thefirst}."
|
||||
mp.msg.Enter.DOOR_NOWHERE = "{#Thefirst} {#present/#first,lead} nowhere."
|
||||
mp.msg.Enter.DOOR_CLOSED = "{#Thefirst} {#is/#first} closed."
|
||||
|
||||
|
@ -418,7 +472,8 @@ mp.msg.Walk.WALK = "But {#thefirst} {#is/#first} already here."
|
|||
mp.msg.Walk.NOWHERE = "Where?"
|
||||
mp.msg.Walk.INV = "{#Me} {#is/#me} holding this."
|
||||
|
||||
mp.msg.Enter.EXITBEFORE = "{#Me} {#present/#me,need} to {#if_has/#where,supporter,get off from,leave} {#thefirst} first."
|
||||
mp.msg.Enter.EXITBEFORE = "{#Me} {#present/#me,need} to "..
|
||||
"{#if_has/#where,supporter,get off from,leave} {#thenoun/#where} first."
|
||||
|
||||
mp.msg.Exit.NOTHERE = "But {#me} {#is/#me} not {#if_has/#first,supporter,on,in} {#thefirst}."
|
||||
mp.msg.Exit.NOWHERE = "But {#me} {#have/#me} no way to exit."
|
||||
|
@ -432,7 +487,7 @@ mp.msg.Inv.INV = "{#Me} {#have/#me}"
|
|||
|
||||
mp.msg.Open.OPEN = "{#Me} {#present/#me,open} {#thefirst}."
|
||||
mp.msg.Open.NOTOPENABLE = "{#Thefirst} {#is/#first} not openable."
|
||||
mp.msg.Open.WHENOPEN = "{#Thenoun/first/} {#is/#first} already opened."
|
||||
mp.msg.Open.WHENOPEN = "{#Thenoun/#first} {#is/#first} already opened."
|
||||
mp.msg.Open.WHENLOCKED = "It's seems that {#thefirst} {#is/#first} locked."
|
||||
|
||||
mp.msg.Close.CLOSE = "{#Me} {#present/#me,close} {#thefirst}."
|
||||
|
@ -608,7 +663,8 @@ mp.msg.Answer.EMPTY = "{#Me} can't find anything to answer."
|
|||
mp.msg.Answer.SELF = "Good answer."
|
||||
|
||||
mp.msg.Yes.YES = "That was a rhetorical question."
|
||||
mp.msg.Buy.USE = "How exactly?"
|
||||
mp.msg.Buy.BUY = "Nothing is on sale."
|
||||
mp.msg.Use.USE = "How exactly?"
|
||||
|
||||
mp.keyboard_space = '<space>'
|
||||
mp.keyboard_backspace = '<backspace>'
|
||||
|
@ -617,21 +673,21 @@ mp.msg.GAMEOVER_HELP = [[Use restart to restart game.]];
|
|||
|
||||
function mp:myself(ob)
|
||||
if ob:hint'first' then
|
||||
return { "myself", "me" }
|
||||
return { "myself", "self", "me" }
|
||||
end
|
||||
if ob:hint'second' then
|
||||
return { "yourself", "me", "myself" }
|
||||
return { "yourself", "myself", "self", "me" }
|
||||
end
|
||||
if ob:hint'plural' then
|
||||
return { "themselves", "our" }
|
||||
return { "themselves", "ourselves", "self" }
|
||||
end
|
||||
if ob:hint'female' then
|
||||
return { "herself", "me" }
|
||||
return { "herself", "myself", "self", "me" }
|
||||
end
|
||||
if ob:hint'male' then
|
||||
return { "himself", "me" }
|
||||
return { "himself", "myself", "self", "me" }
|
||||
end
|
||||
return { "itself" }
|
||||
return { "itself", "myself", "self", "me" }
|
||||
end
|
||||
|
||||
function mp:it(w)
|
||||
|
@ -684,7 +740,8 @@ function mp:before_Enter(w)
|
|||
return false
|
||||
end
|
||||
|
||||
mp.msg.HELP = [[{$fmt b|INSTRUCTIONS}^^
|
||||
mp.msg.HELP = function()
|
||||
p [[{$fmt b|INSTRUCTIONS}^^
|
||||
|
||||
Enter your actions in verb noun form. For example:^
|
||||
> open door^
|
||||
|
@ -698,13 +755,17 @@ To examine whole scene, enter "exam" or press "Enter".^
|
|||
^
|
||||
To exam your inventory, enter "inv".^
|
||||
^
|
||||
Use compass directions to walk. For example: "go north" or "north" or just "n".
|
||||
^^
|
||||
You may use the "TAB" key for autocompletion.
|
||||
]]
|
||||
Use compass directions to walk. For example: "go north" or "north" or just "n". There are also up and down directions, outside and inside.]]
|
||||
if not instead.tiny then
|
||||
p [[^^You may use the "TAB" key for autocompletion.]]
|
||||
end
|
||||
end
|
||||
|
||||
function mp.token.compass1(_)
|
||||
return "{noun_obj}/@n_to,compass|{noun_obj}/@ne_to,compass|{noun_obj}/@e_to,compass|{noun_obj}/@se_to,compass|{noun_obj}/@s_to,compass|{noun_obj}/@sw_to,compass|{noun_obj}/@w_to,compass|{noun_obj}/@nw_to,compass"
|
||||
return "{noun_obj}/@n_to,compass|{noun_obj}/@ne_to,compass|"..
|
||||
"{noun_obj}/@e_to,compass|{noun_obj}/@se_to,compass|"..
|
||||
"{noun_obj}/@s_to,compass|{noun_obj}/@sw_to,compass|"..
|
||||
"{noun_obj}/@w_to,compass|{noun_obj}/@nw_to,compass"
|
||||
end
|
||||
|
||||
function mp.token.compass2(_)
|
||||
|
@ -713,15 +774,29 @@ end
|
|||
|
||||
std.mod_init(function(_)
|
||||
Verb { "#Walk",
|
||||
"go,walk,run,enter",
|
||||
"go,walk,run,enter,come",
|
||||
"{compass1} : Walk",
|
||||
"in|into|inside {noun}/scene,enterable : Enter",
|
||||
"in|into|inside|on {noun}/scene,enterable : Enter",
|
||||
"{noun}/scene : Walk",
|
||||
"{compass2}: Walk",
|
||||
"outside|out|away: Exit" }
|
||||
"outside|out|away: Exit"
|
||||
}
|
||||
|
||||
Verb { "#Enter",
|
||||
"enter",
|
||||
"{noun}/scene,enterable : Enter"
|
||||
}
|
||||
|
||||
Verb { "#Sit",
|
||||
"sit,stand",
|
||||
"?down in|into|inside|on {noun}/scene,enterable : Enter" }
|
||||
|
||||
Verb { "#Lie",
|
||||
"lie",
|
||||
"down in|into|inside|on {noun}/scene,enterable : Enter" }
|
||||
|
||||
Verb { "#Exit",
|
||||
"exit,out",
|
||||
"exit,out,leave",
|
||||
"?from {noun}/scene : Exit",
|
||||
": Exit"}
|
||||
|
||||
|
@ -732,6 +807,7 @@ Verb { "#Exam",
|
|||
"inventory : Inv",
|
||||
"~ under {noun} : LookUnder",
|
||||
"~ in|inside|into|through|on {noun} : Search",
|
||||
"~ ?at {noun} : Exam",
|
||||
"~ up * in {noun} : Consult reverse",
|
||||
}
|
||||
|
||||
|
@ -818,6 +894,7 @@ Verb {
|
|||
|
||||
Verb {
|
||||
"#Remove",
|
||||
"remove",
|
||||
"~ {noun}/held : Disrobe",
|
||||
"{noun} from {noun} : Remove",
|
||||
"~ {noun}/scene : Take",
|
||||
|
@ -833,6 +910,7 @@ Verb {
|
|||
|
||||
Verb {
|
||||
"#SwitchOff",
|
||||
"switch",
|
||||
"off {noun}: SwitchOff",
|
||||
"~ {noun} off : SwitchOff",
|
||||
}
|
||||
|
@ -959,7 +1037,7 @@ Verb {
|
|||
|
||||
Verb {
|
||||
"#Listen",
|
||||
"listen.hear",
|
||||
"listen,hear",
|
||||
"Listen",
|
||||
"?to {noun}: Listen",
|
||||
}
|
||||
|
@ -1070,8 +1148,7 @@ Verb {
|
|||
Verb {
|
||||
"#Talk",
|
||||
"talk",
|
||||
"with {noun}/live : Talk"
|
||||
|
||||
"with|to {noun}/live : Talk"
|
||||
}
|
||||
|
||||
Verb {
|
||||
|
@ -1160,6 +1237,8 @@ MetaVerb {
|
|||
"~parser",
|
||||
"expert on : MetaExpertOn",
|
||||
"expert off : MetaExpertOff",
|
||||
"verbs : MetaVerbs",
|
||||
"version : MetaVersion",
|
||||
}
|
||||
|
||||
MetaVerb {
|
||||
|
@ -1199,12 +1278,18 @@ std.mod_start(function()
|
|||
"MetaUndo",
|
||||
}
|
||||
end
|
||||
if mp.score then
|
||||
MetaVerb {
|
||||
"~ счёт",
|
||||
"MetaScore",
|
||||
}
|
||||
end
|
||||
end)
|
||||
-- Dialog
|
||||
std.phr.default_Event = "Exam"
|
||||
|
||||
Verb ({"~ say", "{select} : Exam" }, std.dlg)
|
||||
Verb ({'#Next', "more|next", "Next" }, mp.cutscene)
|
||||
Verb ({'#Next', "more,next", "Next" }, mp.cutscene)
|
||||
Verb ({'#Exam', "~ exam/ine", "Look" }, std.dlg)
|
||||
|
||||
mp.cutscene.default_Verb = "more"
|
||||
|
|
289
parser/mp-ru.lua
289
parser/mp-ru.lua
|
@ -67,7 +67,40 @@ function mp:skip_filter(w)
|
|||
return true
|
||||
end
|
||||
|
||||
_'@compass'.before_Default = 'Попробуйте глагол "идти".'
|
||||
local function endswith(w, t)
|
||||
return not not w:find(t..'$')
|
||||
end
|
||||
|
||||
function mp:verb_filter(w)
|
||||
if #w > 1 then
|
||||
return true
|
||||
end
|
||||
local utf = mp.utf
|
||||
local verb = w[1]
|
||||
local t = utf.chars(w[1])
|
||||
if endswith(verb, 'ся') or endswith(verb, 'сь') or endswith(verb, 'те') then
|
||||
local len = #verb
|
||||
len = len - utf.bb(verb, len)
|
||||
len = len - utf.bb(verb, len)
|
||||
verb = verb:sub(1, len)
|
||||
end
|
||||
if endswith(verb, 'и') or endswith(verb, 'ь') then
|
||||
return true
|
||||
end
|
||||
local t = utf.chars(verb)
|
||||
local a = { ['а'] = true, ['е'] = true, ['и'] = true,
|
||||
['о'] = true, ['у'] = true, ['ы'] = true,
|
||||
['ю'] = true, ['я'] = true };
|
||||
local len = #t
|
||||
if len >= 2 and a[t[len - 1]] and t[len] == 'й' then -- or a[t[len]] then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
_'@compass'.before_Default = function()
|
||||
p('"{#First}" это направление. {#Firstit/вн} нельзя ', mp.parsed[1], ".")
|
||||
end
|
||||
|
||||
function mp.msg.SCORE(d)
|
||||
if d > 0 then
|
||||
|
@ -77,8 +110,16 @@ function mp.msg.SCORE(d)
|
|||
end
|
||||
end
|
||||
mp.door.word = -"дверь";
|
||||
mp.msg.TITLE_SCORE = "Счёт: "
|
||||
mp.msg.TITLE_TURNS = "Ходы: "
|
||||
mp.msg.TITLE_SCORE = function()
|
||||
if mp.maxscore then
|
||||
pr ("Счёт: ", mp.score, "/", mp.maxscore)
|
||||
else
|
||||
pr ("Счёт: ", mp.score)
|
||||
end
|
||||
end
|
||||
mp.msg.TITLE_TURNS = function()
|
||||
pr ("Ходы: ", game:time() - 1)
|
||||
end
|
||||
mp.msg.YES = "Да"
|
||||
mp.msg.WHEN_DARK = "Кромешная тьма."
|
||||
mp.msg.UNKNOWN_THEDARK = "Возможно, это потому что в темноте ничего не видно?"
|
||||
|
@ -130,11 +171,25 @@ end
|
|||
|
||||
mp.msg.enter = "<ввод>"
|
||||
mp.msg.EMPTY = 'Простите?'
|
||||
mp.msg.UNKNOWN_VERB = "Непонятный глагол"
|
||||
mp.msg.UNKNOWN_VERB_HINT = "Возможно, вы имели в виду"
|
||||
mp.msg.UNKNOWN_VERB = function(w)
|
||||
p ("Непонятный глагол ", iface:em(w), ".")
|
||||
end
|
||||
mp.msg.UNKNOWN_VERB_HINT = function(w)
|
||||
p ("Самое похожее слово: ", iface:em(w), ".")
|
||||
end
|
||||
mp.msg.INCOMPLETE = "Нужно дополнить предложение."
|
||||
mp.msg.INCOMPLETE_NOUN = "К чему вы хотите применить команду"
|
||||
mp.msg.INCOMPLETE_SECOND_NOUN = "Уточните команду:"
|
||||
mp.msg.INCOMPLETE_NOUN = function(w)
|
||||
if w then
|
||||
p('К чему вы хотите применить команду "',w, '"?')
|
||||
else
|
||||
p"К чему вы хотите применить команду?"
|
||||
end
|
||||
end
|
||||
|
||||
mp.msg.INCOMPLETE_SECOND_NOUN = function(w)
|
||||
p ('Уточните команду: "',w,'"?')
|
||||
end
|
||||
|
||||
mp.msg.UNKNOWN_OBJ = function(w)
|
||||
if not w then
|
||||
p "Об этом предмете ничего не известно."
|
||||
|
@ -152,10 +207,9 @@ mp.msg.UNKNOWN_WORD = function(w)
|
|||
p ("(",w,"?).")
|
||||
end
|
||||
end
|
||||
mp.msg.HINT_WORDS = "Может быть"
|
||||
mp.msg.HINT_OR = "или"
|
||||
mp.msg.HINT_AND = "и"
|
||||
mp.msg.HINT_WORDS = "Возможно"
|
||||
mp.msg.AND = "и"
|
||||
mp.msg.OR = "или"
|
||||
mp.msg.MULTIPLE = "Тут есть"
|
||||
mp.msg.LIVE_ACTION = function(w)
|
||||
p (w:It'дт'," это не понравится.")
|
||||
|
@ -166,16 +220,28 @@ mp.msg.NOTINV = function(t)
|
|||
p (lang.cap(t:noun'вн') .. " сначала нужно взять.")
|
||||
end
|
||||
--"надет"
|
||||
mp.msg.WORN = function(w)
|
||||
mp.msg.HAS_WORN = function(w)
|
||||
local hint = w:gram().hint
|
||||
pr (" (",mp.mrd:word('надет/' .. hint), ")")
|
||||
return mp.mrd:word('надет/' .. hint)
|
||||
end
|
||||
--"открыт"
|
||||
mp.msg.OPEN = function(w)
|
||||
mp.msg.HAS_OPEN = function(w)
|
||||
local hint = w:gram().hint
|
||||
pr (" (",mp.mrd:word('открыт/' .. hint), ")")
|
||||
return mp.mrd:word('открыт/' .. hint)
|
||||
end
|
||||
mp.msg.EXITBEFORE = "Возможно, {#me/дт} нужно сначала {#if_has/#where,supporter,слезть с {#where/рд}.,покинуть {#where/вн}.}"
|
||||
--"включён"
|
||||
mp.msg.HAS_ON = function(w)
|
||||
local hint = w:gram().hint
|
||||
return mp.mrd:word('включён/' .. hint)
|
||||
end
|
||||
--"светится"
|
||||
mp.msg.HAS_LIGHT = function(w)
|
||||
local hint = w:gram().hint
|
||||
return mp.mrd:word('светится/' .. hint)
|
||||
end
|
||||
|
||||
mp.msg.EXITBEFORE = "Возможно, {#me/дт} нужно сначала "..
|
||||
"{#if_has/#where,supporter,слезть с {#where/рд}.,покинуть {#where/вн}.}"
|
||||
|
||||
mp.default_Event = "Exam"
|
||||
mp.default_Verb = "осмотреть"
|
||||
|
@ -186,7 +252,6 @@ mp.msg.ACCESS2 = "{#Second} отсюда не{#word/доступен,#second}."
|
|||
|
||||
mp.msg.Look.HEREIS = "Здесь находится"
|
||||
mp.msg.Look.HEREARE = "Здесь находятся"
|
||||
|
||||
mp.msg.NOROOM = function(w)
|
||||
if w == std.me() then
|
||||
p ("У {#me/рд} слишком много вещей.")
|
||||
|
@ -199,11 +264,47 @@ end
|
|||
--"включён"
|
||||
--"выключен"
|
||||
mp.msg.Exam.SWITCHSTATE = "{#First} сейчас {#if_has/#first,on,{#word/включён,#first},{#word/выключен,#first}}."
|
||||
mp.msg.Exam.NOTHING = "ничего нет."
|
||||
mp.msg.Exam.IS = "находится"
|
||||
mp.msg.Exam.ARE = "находятся"
|
||||
mp.msg.Exam.IN = "В {#first/пр,2}"
|
||||
mp.msg.Exam.ON = "На {#first/пр,2}"
|
||||
|
||||
mp.msg.Exam.NOTHING = function(w)
|
||||
if w:has 'supporter' then
|
||||
mp:pnoun (w, "На {#first/пр,2}")
|
||||
else
|
||||
mp:pnoun (w, "В {#first/пр,2}")
|
||||
end
|
||||
p "ничего нет."
|
||||
end
|
||||
|
||||
mp.msg.Exam.CONTENT = function(w, oo)
|
||||
local single = #oo == 1 and not oo[1]:hint 'plural'
|
||||
if std.me():where() == w or std.here() == w then
|
||||
if false then
|
||||
if single then
|
||||
p "Здесь находится"
|
||||
else
|
||||
p "Здесь находятся"
|
||||
end
|
||||
mp:multidsc(oo)
|
||||
else
|
||||
p "{#Me} {#word/видеть,#me,нст} здесь";
|
||||
mp:multidsc(oo, 'вн')
|
||||
end
|
||||
p "."
|
||||
return
|
||||
end
|
||||
if w:has 'supporter' then
|
||||
mp:pnoun (w, "На {#first/пр,2}")
|
||||
else
|
||||
mp:pnoun (w, "В {#first/пр,2}")
|
||||
end
|
||||
if single then
|
||||
p "находится"
|
||||
else
|
||||
p "находятся"
|
||||
end
|
||||
mp:multidsc(oo)
|
||||
p "."
|
||||
end
|
||||
|
||||
--"видеть"
|
||||
mp.msg.Exam.DEFAULT = "{#Me} не {#word/видеть,#me,нст} {#vo/{#first/пр}} ничего необычного.";
|
||||
mp.msg.Exam.SELF = "{#Me} не {#word/видеть,#me,нст} в себе ничего необычного.";
|
||||
|
@ -240,7 +341,8 @@ mp.msg.Exit.CLOSED = "Но {#first} {#word/закрыт,#first}."
|
|||
|
||||
--"покидать"
|
||||
--"слезать"
|
||||
mp.msg.Exit.EXITED = "{#Me} {#if_has/#first,supporter,{#word/слезать с,#me,нст} {#first/рд},{#word/покидать,#me,нст} {#first/вн}}."
|
||||
mp.msg.Exit.EXITED = "{#Me} {#if_has/#first,supporter,{#word/слезать {#so/{#first/рд},#me,нст}},"..
|
||||
"{#word/покидать,#me,нст} {#first/вн}}."
|
||||
|
||||
mp.msg.GetOff.NOWHERE = "Но {#me/дт} не с чего слезать."
|
||||
|
||||
|
@ -294,8 +396,11 @@ mp.msg.Take.SCENERY = "{#First/вн} невозможно взять."
|
|||
mp.msg.Take.WORN = "{#First} {#word/надет,#first} на {#firstwhere/вн}."
|
||||
mp.msg.Take.PARTOF = "{#First} {#if_hint/#first,plural,являются,является} частью {#firstwhere/рд}."
|
||||
|
||||
mp.msg.Remove.WHERE = "{#First} не находится {#if_has/#second,supporter,на,в} {#second/пр,2}."
|
||||
mp.msg.Remove.REMOVE = "{#First} {#if_has/#second,supporter,поднят,извлечён из} {#second/рд}."
|
||||
mp.msg.Remove.WHERE = "{#First} не {#word/находиться,#first,нст} {#if_has/#second,supporter,на,в} {#second/пр,2}."
|
||||
--"поднят"
|
||||
--"извлечён"
|
||||
mp.msg.Remove.REMOVE = "{#First} {#if_has/#second,supporter,{#word/поднят с,#first},"..
|
||||
"{#word/извлечён из,#first}} {#second/рд}."
|
||||
|
||||
mp.msg.Drop.SELF = "У {#me/рд} не хватит ловкости."
|
||||
mp.msg.Drop.WORN = "{#First/вн} сначала нужно снять."
|
||||
|
@ -480,13 +585,13 @@ end
|
|||
|
||||
function mp:myself(_, hint)
|
||||
local ww = dict({
|
||||
["вн"] = "себя";
|
||||
["дт"] = "себе";
|
||||
["тв"] = "собой";
|
||||
["пр"] = "себе";
|
||||
["рд"] = "себя";
|
||||
["вн"] = { "себя" };
|
||||
["дт"] = { "себе" };
|
||||
["тв"] = {"собой" };
|
||||
["пр"] = { "себе" };
|
||||
["рд"] = { "себя" };
|
||||
}, hint)
|
||||
return { ww }
|
||||
return ww
|
||||
end
|
||||
|
||||
function mp:it(w, hint)
|
||||
|
@ -560,27 +665,52 @@ function mp:err_noun(noun)
|
|||
end
|
||||
|
||||
function mp.shortcut.vo(hint)
|
||||
local w = std.split(mp.mrd.lang.norm(hint))
|
||||
local utf = mp.utf
|
||||
local vow = lang.is_vowel
|
||||
local char = utf.char
|
||||
local excl = {
|
||||
["льве"] = true,
|
||||
["львах"] = true,
|
||||
["льду"] = true,
|
||||
["льдах"] = true,
|
||||
["льне"] = true,
|
||||
["льнах"] = true,
|
||||
["лбу"] = true,
|
||||
["лбах"] = true,
|
||||
["лжи"] = true,
|
||||
["лжах"] = true,
|
||||
["мху"] = true,
|
||||
["мхах"] = true,
|
||||
["рву"] = true,
|
||||
["рвах"] = true,
|
||||
["ржи"] = true,
|
||||
["ржах"] = true,
|
||||
["рту"] = true,
|
||||
["ртах"] = true,
|
||||
["мне"] = true,
|
||||
["что"] = true,
|
||||
}
|
||||
w = w[#w]
|
||||
if mp.utf.len(w) > 2 and
|
||||
(vow(char(w, 1) == 'в' or vow(char(w, 1) == 'ф') and
|
||||
not vow(char(w, 2)))) or excl[w] then
|
||||
return "во ".. hint
|
||||
end
|
||||
return "в ".. hint
|
||||
-- local w = std.split(hint)
|
||||
-- w = w[#w]
|
||||
-- if mp.utf.len(w) > 2 and
|
||||
-- (lang.is_vowel(utf.char(w, 1)) or
|
||||
-- lang.is_vowel(utf.char(w, 2))) then
|
||||
-- return "в ".. hint
|
||||
-- end
|
||||
-- return "во ".. hint
|
||||
end
|
||||
|
||||
function mp.shortcut.so(hint)
|
||||
local w = std.split(mp.mrd.lang.norm(hint))
|
||||
local utf = mp.utf
|
||||
w = w[#w]
|
||||
if utf.len(w) > 2 and
|
||||
(not lang.is_vowel(utf.char(w, 1) and
|
||||
not lang.is_vowel(utf.char(w, 2))))
|
||||
or utf.char(w, 1) == 'щ' then
|
||||
return "со ".. hint
|
||||
end
|
||||
return "с ".. hint
|
||||
-- local w = std.split(hint)
|
||||
-- w = w[#w]
|
||||
-- if mp.utf.len(w) > 2 and
|
||||
-- (lang.is_vowel(utf.char(w, 1)) or
|
||||
-- lang.is_vowel(utf.char(w, 2))) then
|
||||
-- return "с ".. hint
|
||||
-- end
|
||||
-- return "со ".. hint
|
||||
end
|
||||
|
||||
function mp:before_Enter(w)
|
||||
|
@ -591,7 +721,8 @@ function mp:before_Enter(w)
|
|||
return false
|
||||
end
|
||||
|
||||
mp.msg.HELP = [[{$fmt b|КАК ИГРАТЬ?}^^
|
||||
mp.msg.HELP = function()
|
||||
p [[{$fmt b|КАК ИГРАТЬ?}^^
|
||||
|
||||
Вводите ваши действия в виде простых предложений вида: глагол -- существительное. Например:^
|
||||
> открыть дверь^
|
||||
|
@ -607,14 +738,17 @@ mp.msg.HELP = [[{$fmt b|КАК ИГРАТЬ?}^^
|
|||
^
|
||||
Чтобы узнать какие предметы у вас с собой, наберите "инвентарь" или "инв".^
|
||||
^
|
||||
Для перемещений используйте стороны света, например: "идти на север" или "север" или просто "с".^
|
||||
Кроме сторон света можно перемещаться вверх ("вверх" или "вв") и вниз ("вниз" или "вн").
|
||||
^^
|
||||
Вы можете воспользоваться клавишей "TAB" для автодополнения ввода.
|
||||
]]
|
||||
Для перемещений используйте стороны света, например: "идти на север" или "север" или просто "с". Кроме сторон света можно перемещаться вверх ("вверх" или "вв") и вниз ("вниз" или "вн"), "внутрь" и "наружу".]]
|
||||
if not instead.tiny then
|
||||
p [[^^Вы можете воспользоваться клавишей "TAB" для автодополнения ввода.]]
|
||||
end
|
||||
end
|
||||
|
||||
function mp.token.compass1(_)
|
||||
return "{noun_obj}/@n_to,compass|{noun_obj}/@ne_to,compass|{noun_obj}/@e_to,compass|{noun_obj}/@se_to,compass|{noun_obj}/@s_to,compass|{noun_obj}/@sw_to,compass|{noun_obj}/@w_to,compass|{noun_obj}/@nw_to,compass"
|
||||
return "{noun_obj}/@n_to,compass|{noun_obj}/@ne_to,compass|"..
|
||||
"{noun_obj}/@e_to,compass|{noun_obj}/@se_to,compass|"..
|
||||
"{noun_obj}/@s_to,compass|{noun_obj}/@sw_to,compass|"..
|
||||
"{noun_obj}/@w_to,compass|{noun_obj}/@nw_to,compass"
|
||||
end
|
||||
|
||||
function mp.token.compass2(_)
|
||||
|
@ -659,8 +793,8 @@ Verb { "#Exam",
|
|||
"~ в|во|на {noun}/пр,2 : Search",
|
||||
"~ внутри {noun}/рд : Search",
|
||||
"~ в|во {noun}/вн : Search",
|
||||
"~ в|во {noun}/пр,2 о|об|обо|про * : Consult",
|
||||
"~ о|об|обо|про * в|во {noun}/пр,2 : Consult reverse",
|
||||
"~ в|во {noun}/пр,2 ?о|?об|?обо|?про * : Consult",
|
||||
"~ ?о|?об|?обо|?про * в|во {noun}/пр,2 : Consult reverse",
|
||||
}
|
||||
|
||||
Verb { "#Search",
|
||||
|
@ -668,8 +802,8 @@ Verb { "#Search",
|
|||
"{noun}/вн : Search",
|
||||
"в|во|на {noun}/пр,2 : Search",
|
||||
"под {noun}/тв : LookUnder",
|
||||
"~ в|во {noun}/пр,2 * : Consult",
|
||||
"~ * в|во {noun}/пр,2 : Consult reverse",
|
||||
"~ в|во {noun}/пр,2 ?о|?об|?обо|?про * : Consult",
|
||||
"~ ?о|?об|?обо|?про * в|во {noun}/пр,2 : Consult reverse",
|
||||
}
|
||||
|
||||
Verb { "#Open",
|
||||
|
@ -721,7 +855,7 @@ Verb { "#Take",
|
|||
}
|
||||
|
||||
Verb { "#Insert",
|
||||
"воткн/уть,втык/ать,вставить,влож/ить",
|
||||
"воткн/уть,втык/ать,вставить,влож/ить,"..
|
||||
"[|про|за]сун/уть,вставь/",
|
||||
"{noun}/вн,held в|во {noun}/вн,inside : Insert",
|
||||
"~ {noun}/вн,held внутрь {noun}/рд : Insert",
|
||||
|
@ -742,7 +876,7 @@ Verb { "#Drop",
|
|||
|
||||
Verb {
|
||||
"#ThrowAt",
|
||||
"брос/ить,выбро/сить,кин/уть,кида/ть,швыр/нуть,метн/уть,метать",
|
||||
"брос/ить,выбро/сить,кину/ть,кинь/,кида/ть,швыр/нуть,метн/уть,метать",
|
||||
"{noun}/вн,held : Drop",
|
||||
"{noun}/вн,held в|во|на {noun}/вн : ThrowAt",
|
||||
"~ в|во|на {noun}/вн {noun}/вн : ThrowAt reverse",
|
||||
|
@ -878,7 +1012,7 @@ Verb {
|
|||
"[|под]жечь,жг/и,подожги/,поджиг/ай,зажг/и,зажиг/ай,зажечь",
|
||||
"{noun}/вн : Burn",
|
||||
"{noun}/вн {noun}/тв,held : Burn",
|
||||
"~ {noun}/тв,held {noun}/вн reverse",
|
||||
"~ {noun}/тв,held {noun}/вн : Burn reverse",
|
||||
}
|
||||
|
||||
Verb {
|
||||
|
@ -1053,7 +1187,7 @@ Verb {
|
|||
"сказать,сообщи/ть,сообщу,рассказать,расскаж/ите",
|
||||
"{noun}/дт,live о|об|обо|про * : Tell",
|
||||
"~ * {noun}/дт,live : Tell reverse",
|
||||
"~ {noun}/дт * : AskTo",
|
||||
"~ {noun}/дт * : Tell"
|
||||
}
|
||||
|
||||
Verb {
|
||||
|
@ -1098,6 +1232,26 @@ Verb {
|
|||
}
|
||||
|
||||
if DEBUG then
|
||||
|
||||
function mp:MetaForm(w)
|
||||
if not w then return end
|
||||
local t, hint
|
||||
w = w:gsub("_", "/")
|
||||
if w:find "/" then
|
||||
hint = true
|
||||
end
|
||||
for _, f in ipairs { "им", "рд", "дт", "вн", "тв", "пр", "пр,2" } do
|
||||
local ww = w
|
||||
if hint then
|
||||
ww = ww .. ','.. f
|
||||
else
|
||||
ww = ww .. '/' .. f
|
||||
end
|
||||
t = self.mrd:word(ww)
|
||||
pn(t, " (", f, ")")
|
||||
end
|
||||
end
|
||||
|
||||
MetaVerb {
|
||||
"#MetaWord",
|
||||
"~_слово",
|
||||
|
@ -1119,6 +1273,11 @@ if DEBUG then
|
|||
"~_дамп",
|
||||
"MetaDump"
|
||||
}
|
||||
MetaVerb {
|
||||
"#МетаForm",
|
||||
"~_форм/ы",
|
||||
"* :MetaForm"
|
||||
}
|
||||
end
|
||||
MetaVerb {
|
||||
"#MetaTranscript",
|
||||
|
@ -1133,6 +1292,8 @@ MetaVerb {
|
|||
"~парсер",
|
||||
"эксперт да : MetaExpertOn",
|
||||
"эксперт нет : MetaExpertOff",
|
||||
"глаголы : MetaVerbs",
|
||||
"версия : MetaVersion",
|
||||
}
|
||||
|
||||
MetaVerb {
|
||||
|
@ -1177,6 +1338,12 @@ std.mod_start(function()
|
|||
"MetaUndo",
|
||||
}
|
||||
end
|
||||
if mp.score then
|
||||
MetaVerb {
|
||||
"~ счёт",
|
||||
"MetaScore",
|
||||
}
|
||||
end
|
||||
end)
|
||||
-- Dialog
|
||||
std.phr.default_Event = "Exam"
|
||||
|
|
230
parser/mp.lua
230
parser/mp.lua
|
@ -1,5 +1,5 @@
|
|||
local curdir = std.getinfo(1).source:gsub("^(.+[\\/])[^\\/]+$", "%1"):gsub("^@", "");
|
||||
|
||||
local table = std.table
|
||||
require "fmt"
|
||||
require "snapshots"
|
||||
|
||||
|
@ -97,6 +97,38 @@ local function utf_chars(b)
|
|||
return res
|
||||
end
|
||||
|
||||
local function utf_similar(str1, str2, lev)
|
||||
local chars1 = utf_chars(str1)
|
||||
local chars2 = utf_chars(str2)
|
||||
local len1 = #chars1
|
||||
local len2 = #chars2
|
||||
if len1 < lev or len2 < lev then
|
||||
return false
|
||||
end
|
||||
|
||||
for i = 0, len2 - lev do
|
||||
local ok = true
|
||||
for k = 1, lev do
|
||||
if chars1[k] ~= chars2[i + k] then
|
||||
ok = false
|
||||
break
|
||||
end
|
||||
end
|
||||
if ok then return true end
|
||||
end
|
||||
|
||||
for i = 0, len1 - lev do
|
||||
local ok = true
|
||||
for k = 1, lev do
|
||||
if chars2[k] ~= chars1[i + k] then
|
||||
ok = false
|
||||
break
|
||||
end
|
||||
end
|
||||
if ok then return true end
|
||||
end
|
||||
return false
|
||||
end
|
||||
--- Returns the Levenshtein distance between the two given strings.
|
||||
-- https://gist.github.com/Badgerati/3261142
|
||||
|
||||
|
@ -194,6 +226,9 @@ end
|
|||
|
||||
function input:key(press, key)
|
||||
local mod
|
||||
if mp:noparser() then
|
||||
return false
|
||||
end
|
||||
if key:find("alt") then
|
||||
mp.alt = press
|
||||
mod = true
|
||||
|
@ -220,7 +255,9 @@ end
|
|||
|
||||
mp = std.obj {
|
||||
nam = '@metaparser';
|
||||
started = false;
|
||||
score = false;
|
||||
maxscore = false;
|
||||
expert_mode = true;
|
||||
autohelp = false;
|
||||
autohelp_limit = 1000;
|
||||
|
@ -234,7 +271,7 @@ mp = std.obj {
|
|||
detailed_inv = false;
|
||||
daemons = std.list {};
|
||||
{
|
||||
version = "1.10";
|
||||
version = "2.2";
|
||||
cache = { tokens = {}, nouns = false };
|
||||
scope = std.list {};
|
||||
logfile = false;
|
||||
|
@ -251,6 +288,7 @@ mp = std.obj {
|
|||
ff = std.rawget(_G, 'utf8_next') or utf_ff;
|
||||
len = std.rawget(_G, 'utf8_len') or utf_len;
|
||||
char = std.rawget(_G, 'utf8_char') or utf_char;
|
||||
chars = utf_chars;
|
||||
};
|
||||
lev_thresh = 3;
|
||||
lev_ratio = 0.20;
|
||||
|
@ -340,7 +378,14 @@ function mp:key(key)
|
|||
self:autoscript()
|
||||
return true
|
||||
end
|
||||
|
||||
if key == 'home' or key == '[7]' then
|
||||
self.cur = 1
|
||||
return true
|
||||
end
|
||||
if key == 'end' or key == '[1]' then
|
||||
self.cur = self.inp:len() + 1
|
||||
return true
|
||||
end
|
||||
if key == 'left' then
|
||||
return self:inp_left()
|
||||
end
|
||||
|
@ -601,19 +646,23 @@ function mp.token.noun(w)
|
|||
for _, o in ipairs(oo) do
|
||||
local d = {}
|
||||
local r = o:noun(attr, d)
|
||||
if o == std.me() and mp.myself then
|
||||
for _, vm in ipairs(mp:myself(o, w.morph) or {}) do
|
||||
table.insert(ww, { optional = w.optional, word = vm, morph = attr, ob = o, alias = o.alias,
|
||||
hidden = w.hidden or _ ~= 1 })
|
||||
end
|
||||
end
|
||||
if o ~= std.me() or (not o:hint'first' and not o:hint'second') then
|
||||
for k, v in ipairs(d) do
|
||||
local hidden = (k ~= 1) or w.hidden
|
||||
if o:has 'multi' then
|
||||
hidden = w.hidden or (v.idx ~= 1)
|
||||
end
|
||||
if o == std.me() and mp.myself then
|
||||
for _, vm in ipairs(mp:myself(o, w.morph)) do
|
||||
table.insert(ww, { optional = w.optional, word = vm, morph = attr, ob = o, alias = o.alias, hidden = hidden })
|
||||
end
|
||||
break
|
||||
else
|
||||
table.insert(ww, { optional = w.optional, word = r[k], ob = o, morph = attr, alias = v.alias, hidden = hidden })
|
||||
end
|
||||
table.insert(ww,
|
||||
{ optional = w.optional,
|
||||
word = r[k], ob = o,
|
||||
morph = attr, alias = v.alias,
|
||||
hidden = hidden })
|
||||
end
|
||||
if o == mp.first_it then
|
||||
table.insert(syms, 1, o)
|
||||
|
@ -621,6 +670,7 @@ function mp.token.noun(w)
|
|||
table.insert(syms, o)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- for k = 1, #syms do
|
||||
-- table.insert(oo, k, syms[k])
|
||||
|
@ -679,6 +729,11 @@ function mp:eq(t1, t2, lev)
|
|||
return self:__startswith(t2, t)
|
||||
end
|
||||
if lev then
|
||||
t1 = self:norm(t1)
|
||||
t2 = self:norm(t2)
|
||||
if not utf_similar(t1, t2, 3) then -- 3 is hardcoded
|
||||
return false
|
||||
end
|
||||
local l = utf_lev(t1, t2)
|
||||
if l < lev and l / (utf_len(t1) + utf_len(t2)) <= self.lev_ratio then
|
||||
return l
|
||||
|
@ -698,7 +753,7 @@ end
|
|||
|
||||
function mp:pattern(t, delim)
|
||||
local words = {}
|
||||
local pat = str_split(self:norm(t), delim or "|")
|
||||
local pat = str_split(t, delim or "|")
|
||||
for _, v in ipairs(pat) do
|
||||
local w = { }
|
||||
local ov = v
|
||||
|
@ -929,6 +984,14 @@ function mp:skip_filter()
|
|||
return true
|
||||
end
|
||||
|
||||
function mp:ignore_filter(w)
|
||||
return false
|
||||
end
|
||||
|
||||
function mp:verb_filter(words)
|
||||
return true
|
||||
end
|
||||
|
||||
function mp:lookup_verb(words, lev)
|
||||
local ret = {}
|
||||
local w = self:verbs()
|
||||
|
@ -938,8 +1001,18 @@ function mp:lookup_verb(words, lev)
|
|||
local verb = vv.word .. (vv.morph or "")
|
||||
local i, len, rlev
|
||||
i, len, rlev = word_search(words, verb, lev and self.lev_thresh)
|
||||
if not i and not lev and verb ~= vv.word then
|
||||
if not i and not lev and vv.morph then
|
||||
i, len = self:lookup_short(words, vv.word)
|
||||
if i then
|
||||
local v = {}
|
||||
for k = i, i + len - 1 do
|
||||
table.insert(v, words[k])
|
||||
end
|
||||
if verb:find(table.concat(v, ' '), 1, true) ~= 1 and
|
||||
not self:verb_filter(v) then
|
||||
i = false
|
||||
end
|
||||
end
|
||||
end
|
||||
if i and i > 1 and not self:skip_filter({words[i - 1]}) then
|
||||
i = nil
|
||||
|
@ -1184,11 +1257,12 @@ function mp:compl_filter(v)
|
|||
hidden = not v.ob.hint_noun
|
||||
end
|
||||
end
|
||||
if hidden and self.compl_thresh == 0 then
|
||||
local _, pre = self:compl_ctx()
|
||||
local nsym = mp.utf.len(pre)
|
||||
if hidden and self.compl_thresh == 0 and nsym == 0 then
|
||||
return false
|
||||
end
|
||||
local _, pre = self:compl_ctx()
|
||||
if mp.utf.len(pre) < self.compl_thresh then
|
||||
if nsym < self.compl_thresh then
|
||||
return false
|
||||
end
|
||||
if not v.ob or not v.morph then
|
||||
|
@ -1294,6 +1368,7 @@ function mp:compl_ctx_poss()
|
|||
table.insert(res, v)
|
||||
end
|
||||
end
|
||||
res.eol = ctx.eol
|
||||
return res
|
||||
end
|
||||
|
||||
|
@ -1308,6 +1383,7 @@ function mp:compl(str)
|
|||
collectgarbage("stop")
|
||||
self:compl_ctx_current();
|
||||
poss = self:compl_ctx_poss()
|
||||
eol = poss.eol
|
||||
if (#poss == 0 and e) or #words == 0 then -- no context
|
||||
if #words == 0 or (#words == 1 and not e) then -- verb?
|
||||
poss, eol = self:compl_verb(words)
|
||||
|
@ -1323,13 +1399,16 @@ function mp:compl(str)
|
|||
end
|
||||
else -- matches
|
||||
self.cache.nouns = self:nouns()
|
||||
poss, eol, vargs = self:compl_match(words)
|
||||
poss, eol = self:compl_match(words)
|
||||
end
|
||||
poss.eol = eol
|
||||
self:compl_ctx_push(poss)
|
||||
end
|
||||
local _, pre = self:compl_ctx()
|
||||
for _, v in ipairs(poss) do
|
||||
if v.word == '*' then vargs = true end
|
||||
if v.word == '*' and not v.hidden then
|
||||
vargs = true
|
||||
end
|
||||
if self:startswith(v.word, pre) and not v.word:find("%*$") then
|
||||
if not dups[v.word] then
|
||||
dups[v.word] = v
|
||||
|
@ -1446,14 +1525,13 @@ function mp:match(verb, w, compl)
|
|||
local hints = {}
|
||||
local unknown = {}
|
||||
local multi = {}
|
||||
local vargs
|
||||
local parsed_verb = {}
|
||||
local fixed_verb = verb.verb[verb.word_nr]
|
||||
fixed_verb = fixed_verb.word .. (fixed_verb.morph or '')
|
||||
table.insert(parsed_verb, fixed_verb)
|
||||
for _, d in ipairs(verb.dsc) do -- verb variants
|
||||
-- local was_noun = false
|
||||
local match = { args = {}, vargs = {}, ev = d.ev, wildcards = 0, verb = parsed_verb, defaults = 0 }
|
||||
local match = { args = {}, vargs = {}, skip = 0, ev = d.ev, wildcards = 0, verb = parsed_verb, defaults = 0 }
|
||||
local a = {}
|
||||
found = (#d.pat == 0)
|
||||
for k, v in ipairs(w) do
|
||||
|
@ -1466,9 +1544,10 @@ function mp:match(verb, w, compl)
|
|||
local rlev = 1
|
||||
local need_required = false
|
||||
local default = false
|
||||
local vargs
|
||||
for lev, v in ipairs(d.pat) do -- pattern arguments
|
||||
if v == '*' or v == '~*' then
|
||||
vargs = true -- found
|
||||
vargs = v -- found
|
||||
v = '*'
|
||||
end
|
||||
local noun = not not v:find("^~?{noun}")
|
||||
|
@ -1486,18 +1565,19 @@ function mp:match(verb, w, compl)
|
|||
need_required = true
|
||||
all_optional = false
|
||||
end
|
||||
if pp.default then
|
||||
default = pp.default
|
||||
if default then
|
||||
word = pp.word
|
||||
default = true
|
||||
end
|
||||
local new_wildcard
|
||||
local k, len = word_search(a, pp.word)
|
||||
if not k and mp.compare_len > 0 then
|
||||
if not k and mp.compare_len > 0 and not pp.synonym then
|
||||
k, len = word_search(a, pp.word, starteq)
|
||||
new_wildcard = true
|
||||
else
|
||||
new_wildcard = false
|
||||
end
|
||||
if not required and k ~= 1 then k = false end -- ?word is only in 1st pos
|
||||
if k and ((k < best or len > best_len) or
|
||||
(not new_wildcard and wildcard and k <= best and len >= best_len)) then
|
||||
wildcard = new_wildcard
|
||||
|
@ -1552,19 +1632,27 @@ function mp:match(verb, w, compl)
|
|||
break
|
||||
end
|
||||
rlev = rlev + 1
|
||||
end
|
||||
if (wildcard or match.wildcards > 0) and best > 1 then -- do not skip words if wildcard used
|
||||
found = false
|
||||
vargs = false
|
||||
break
|
||||
end
|
||||
-- if false then
|
||||
-- a = tab_exclude(a, best, best + best_len - 1)
|
||||
-- else
|
||||
-- if not was_noun then
|
||||
if not vargs then
|
||||
match.skip = match.skip + (best - 1)
|
||||
for i = 1, best - 1 do
|
||||
table.insert(skip, a[i])
|
||||
end
|
||||
end
|
||||
-- end
|
||||
a = tab_sub(a, best + best_len)
|
||||
-- table.remove(a, 1)
|
||||
-- end
|
||||
vargs = false
|
||||
table.insert(match, word)
|
||||
table.insert(match.args, found)
|
||||
if wildcard then
|
||||
|
@ -1590,9 +1678,14 @@ function mp:match(verb, w, compl)
|
|||
else
|
||||
found = false
|
||||
if #a > 0 or #match.vargs > 0 then
|
||||
table.insert(hints, { word = v, lev = rlev })
|
||||
while #a > 0 do
|
||||
table.insert(match.vargs, a[1])
|
||||
table.insert(match, a[1])
|
||||
table.remove(a, 1)
|
||||
end
|
||||
table.insert(hints, { word = v, lev = rlev, match = match })
|
||||
else
|
||||
table.insert(hints, { word = '*', lev = rlev })
|
||||
table.insert(hints, { word = vargs, lev = rlev, match = match })
|
||||
end
|
||||
end
|
||||
if not found then
|
||||
|
@ -1608,10 +1701,14 @@ function mp:match(verb, w, compl)
|
|||
end
|
||||
end
|
||||
if not compl and mp.errhints then
|
||||
local objs = {}
|
||||
for _, pp in ipairs(pat) do -- single argument
|
||||
if mp.utf.len(pp.word) >= 3 then
|
||||
if not pp.synonym and not objs[pp.ob or 0] then
|
||||
local k, _ = word_search(a, pp.word, self.lev_thresh)
|
||||
if k then table.insert(hints, { word = pp.word, lev = rlev, fuzzy = true, match = match }) end
|
||||
if k then
|
||||
table.insert(hints, { word = pp.word, lev = rlev, fuzzy = true, match = match })
|
||||
objs[pp.ob or 1] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1624,7 +1721,11 @@ function mp:match(verb, w, compl)
|
|||
match.defaults = match.defaults + 1
|
||||
end
|
||||
end
|
||||
if default then
|
||||
table.insert(match.args, { word = word, default = true } )
|
||||
else
|
||||
table.insert(match.args, { word = false, optional = true } )
|
||||
end
|
||||
-- table.insert(hints, { word = v, lev = rlev })
|
||||
found = true
|
||||
end
|
||||
|
@ -1635,6 +1736,7 @@ function mp:match(verb, w, compl)
|
|||
-- end
|
||||
if found or all_optional then
|
||||
match.extra = (#a ~= 0)
|
||||
if not match.extra or match.wildcards == 0 then
|
||||
table.insert(match, 1, fixed_verb) -- w[verb.verb_nr])
|
||||
if self:skip_filter(skip) then
|
||||
table.insert(matches, match)
|
||||
|
@ -1644,20 +1746,29 @@ function mp:match(verb, w, compl)
|
|||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for k, v in ipairs(matches) do
|
||||
v.nr = k
|
||||
--[[
|
||||
if false then
|
||||
print("-----------", k)
|
||||
for kk, vv in ipairs(v) do
|
||||
print(vv)
|
||||
end
|
||||
end
|
||||
]]--
|
||||
end
|
||||
|
||||
table.sort(matches,
|
||||
function(a, b)
|
||||
local na, nb = #a - a.defaults, #b - b.defaults
|
||||
if not a.extra and a.skip == 0 then
|
||||
na = na + 100
|
||||
end
|
||||
if not b.extra and b.skip == 0 then
|
||||
nb = nb + 100
|
||||
end
|
||||
if na == nb and a.wildcards == b.wildcards then
|
||||
return a.nr < b.nr
|
||||
end
|
||||
|
@ -1959,6 +2070,14 @@ function mp:correct(inp)
|
|||
if rinp ~= '' then rinp = rinp .. ' ' end
|
||||
rinp = rinp .. v
|
||||
end
|
||||
local strip_inp = str_split(inp, inp_split)
|
||||
inp = ''
|
||||
for _, v in ipairs(strip_inp) do
|
||||
if not mp:ignore_filter(v) then
|
||||
if inp ~= '' then inp = inp .. ' ' end
|
||||
inp = inp .. v
|
||||
end
|
||||
end
|
||||
local cmprinp = rinp:gsub("["..inp_split.."]+", " ")
|
||||
if not self:eq(cmprinp, inp) then
|
||||
pn(fmt.em("("..rinp..")"))
|
||||
|
@ -1979,7 +2098,7 @@ function mp:show_prompt(inp)
|
|||
if std.cmd[1] == 'look' then
|
||||
return false
|
||||
end
|
||||
if std.here():has 'cutscene' or std.here():has 'noprompt' or player_moved() or std.abort_cmd then
|
||||
if std.here():has 'noprompt' then
|
||||
return false
|
||||
end
|
||||
if self.prompt then
|
||||
|
@ -2044,13 +2163,19 @@ function mp:parse(inp)
|
|||
end
|
||||
|
||||
std.world.display = function(s, state)
|
||||
local l, av, pv
|
||||
if mp.text == '' and game:time() == 1 and state ~= false then
|
||||
local l, av, pv, first
|
||||
if not mp.started and mp.text == '' and game:time() == 1 and state ~= false then
|
||||
local r = std.call(game, 'dsc')
|
||||
if type(r) == 'string' then
|
||||
first = true
|
||||
if mp._pager_mode then
|
||||
mp.text = fmt.anchor() .. r .. '^^' -- .. fmt.anchor()
|
||||
else
|
||||
mp.text = r .. '^^'
|
||||
end
|
||||
end
|
||||
mp.started = true
|
||||
end
|
||||
if mp.clear_on_move and game:time() ~= 1 then
|
||||
if player_moved() then mp:clear() end
|
||||
end
|
||||
|
@ -2070,8 +2195,10 @@ std.world.display = function(s, state)
|
|||
l = std.par(std.scene_delim, reaction or false,
|
||||
av or false, l or false,
|
||||
pv or false) or ''
|
||||
if l ~= '' then
|
||||
mp:log(l)
|
||||
if mp._pager_mode then
|
||||
end
|
||||
if mp._pager_mode and not first then
|
||||
mp.text = mp.text .. fmt.anchor() .. l .. '^^' -- .. fmt.anchor()
|
||||
else
|
||||
mp.text = mp.text .. l .. '^^' -- .. fmt.anchor()
|
||||
|
@ -2258,6 +2385,19 @@ function mp:shorten_input(w)
|
|||
end
|
||||
end
|
||||
|
||||
function mp:strip_input(w)
|
||||
local i = 1
|
||||
local len = #w
|
||||
while i < len do
|
||||
if mp:ignore_filter(w[i]) then
|
||||
table.remove(w, i)
|
||||
len = len - 1
|
||||
else
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function mp:input(str)
|
||||
-- self.cache = { tokens = {} };
|
||||
local hints = {}
|
||||
|
@ -2275,6 +2415,7 @@ function mp:input(str)
|
|||
if not str then return false end
|
||||
end
|
||||
local w = str_split(str, inp_split)
|
||||
mp:strip_input(w)
|
||||
mp:shorten_input(w)
|
||||
self.words = w
|
||||
if #w == 0 then
|
||||
|
@ -2442,12 +2583,13 @@ function(cmd)
|
|||
std.game:__start()
|
||||
end
|
||||
if mp:noparser() then
|
||||
return true, false
|
||||
return
|
||||
end
|
||||
-- mp.inp = mp:docompl(mp.inp)
|
||||
local r, v, n
|
||||
repeat
|
||||
if n then
|
||||
std.busy(true)
|
||||
std.abort_cmd = false
|
||||
std.me():moved(false)
|
||||
std.me():need_scene(false)
|
||||
|
@ -2455,6 +2597,7 @@ function(cmd)
|
|||
r, v = mp:key_enter(cmd[1] == 'look')
|
||||
n = true
|
||||
until not mp:autoplay_pending() or mp:noparser()
|
||||
std.busy(false)
|
||||
mp:onedit()
|
||||
return r, v
|
||||
end
|
||||
|
@ -2471,7 +2614,7 @@ function mp:autoscript(w)
|
|||
end
|
||||
self.autoplay = io.open(w or 'autoscript') or false
|
||||
if self.autoplay then
|
||||
self:MetaTranscriptOn();
|
||||
-- self:MetaTranscriptOn();
|
||||
std.cmd = { 'autoscript' }
|
||||
return true
|
||||
end
|
||||
|
@ -2481,6 +2624,7 @@ end
|
|||
std.mod_init(
|
||||
function()
|
||||
if DEBUG and mp.undo == 0 then mp.undo = 5 end
|
||||
mp:pager_mode(true)
|
||||
_'game'.__daemons = std.list {}
|
||||
end)
|
||||
|
||||
|
@ -2506,10 +2650,10 @@ instead.mouse_filter(0)
|
|||
-- speedup undo
|
||||
local obusy = std.busy
|
||||
local busy_count = 0
|
||||
function std.busy()
|
||||
function std.busy(b)
|
||||
busy_count = busy_count + 1
|
||||
if (busy_count % 100) == 0 then
|
||||
obusy()
|
||||
if not b or (busy_count % 100) == 0 then
|
||||
obusy(b)
|
||||
end
|
||||
end
|
||||
function instead.fading()
|
||||
|
@ -2808,5 +2952,15 @@ function std.obj:has(attr)
|
|||
end
|
||||
|
||||
function iface:title(t)
|
||||
return(iface:bold( mrd.lang.cap(t)))
|
||||
return(iface:bold(mrd.lang.cap(t)))
|
||||
end
|
||||
|
||||
std.getmt("").__pow = function(a, b)
|
||||
if b then
|
||||
if std.is_obj(b) then
|
||||
return b ^ a
|
||||
end
|
||||
return std.rawequal(a, b)
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
|
246
parser/mplib.lua
246
parser/mplib.lua
|
@ -2,7 +2,9 @@
|
|||
--luacheck: no self
|
||||
|
||||
local tostring = std.tostr
|
||||
|
||||
local table = std.table
|
||||
local type = type
|
||||
local string = string
|
||||
--- Error handler
|
||||
-- @param err error code
|
||||
function mp:err(err)
|
||||
|
@ -25,15 +27,14 @@ function mp:err(err)
|
|||
local fixed = verb.verb[verb.word_nr]
|
||||
if verb.verb_nr == 1 then
|
||||
hint = true
|
||||
p (mp:mesg 'UNKNOWN_VERB', " ", iface:em(self.words[verb.verb_nr]), ".")
|
||||
p (mp:mesg 'UNKNOWN_VERB_HINT', " ", iface:em(fixed.word .. (fixed.morph or "")), "?")
|
||||
mp:message('UNKNOWN_VERB', self.words[verb.verb_nr])
|
||||
mp:message('UNKNOWN_VERB_HINT', fixed.word .. (fixed.morph or ""))
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
if not hint then
|
||||
p (mp:mesg('UNKNOWN_VERB') or "Unknown verb:",
|
||||
" ", iface:em(self.words[1]), ".")
|
||||
mp:message('UNKNOWN_VERB', self.words[1])
|
||||
end
|
||||
elseif err == "EMPTY_INPUT" then
|
||||
p (mp:mesg('EMPTY') or "Empty input.")
|
||||
|
@ -47,10 +48,10 @@ function mp:err(err)
|
|||
verb = verb .. vv .. ' '
|
||||
end
|
||||
verb = verb:gsub(" $", "")
|
||||
for _, vv in pairs(self.hints.match.args) do
|
||||
if vv.word then
|
||||
verb = verb .. ' '.. vv.word
|
||||
for _, vv in ipairs(self.hints.match) do
|
||||
verb = verb .. ' '.. vv
|
||||
end
|
||||
for _, vv in pairs(self.hints.match.args) do
|
||||
if vv.ob then
|
||||
second_noun = true
|
||||
end
|
||||
|
@ -96,33 +97,38 @@ function mp:err(err)
|
|||
else
|
||||
if need_noun then
|
||||
if second_noun then
|
||||
p (mp:mesg('INCOMPLETE_SECOND_NOUN') or mp:mesg('INCOMPLETE_NOUN'),
|
||||
" \"", second_noun, " ", mp:err_noun(need_noun), "\"?")
|
||||
elseif parsed then
|
||||
p (mp:mesg('INCOMPLETE_NOUN'), " \"", parsed, "\"?")
|
||||
mp:message('INCOMPLETE_SECOND_NOUN', second_noun .." " ..mp:err_noun(need_noun))
|
||||
else
|
||||
p (mp:mesg('INCOMPLETE_NOUN'), "?")
|
||||
mp:message('INCOMPLETE_NOUN', parsed)
|
||||
end
|
||||
else
|
||||
mp:message 'INCOMPLETE'
|
||||
end
|
||||
end
|
||||
if not mp.errhints then
|
||||
if not mp.errhints or need_noun then
|
||||
return
|
||||
end
|
||||
local words = {}
|
||||
local dups = {}
|
||||
for _, v in ipairs(self.hints) do
|
||||
if v:find("^~?{noun}") or v == '*' then
|
||||
if v:find("^~?{noun}") or v == '*' or v == '~*' then
|
||||
if v:sub(1,1) == '~' then v = v:sub(2) end
|
||||
v = mp:err_noun(v)
|
||||
if not dups[v] and not need_noun then
|
||||
if not dups[v] then
|
||||
table.insert(words, v)
|
||||
dups[v] = true
|
||||
end
|
||||
else
|
||||
local pat = self:pattern(v)
|
||||
local empty = true
|
||||
for _, vv in ipairs(pat) do
|
||||
if not vv.hidden and not dups[vv.word] then
|
||||
if not vv.hidden then
|
||||
empty = false
|
||||
break
|
||||
end
|
||||
end
|
||||
for _, vv in ipairs(pat) do
|
||||
if (empty or not vv.hidden) and not dups[vv.word] then
|
||||
table.insert(words, vv.word)
|
||||
dups[vv.word] = true
|
||||
end
|
||||
|
@ -139,14 +145,14 @@ function mp:err(err)
|
|||
end
|
||||
p (mp:mesg 'HINT_WORDS', ", ", parsed or '')
|
||||
else
|
||||
p (mp:mesg 'HINT_WORDS', " ")
|
||||
p (mp:mesg 'HINT_WORDS', ", ")
|
||||
end
|
||||
end
|
||||
|
||||
for k, v in ipairs(words) do
|
||||
if k ~= 1 then
|
||||
if k == #words then
|
||||
pr (" ", mp.msg.HINT_OR, " ")
|
||||
pr (" ", mp.msg.OR, " ")
|
||||
else
|
||||
pr (", ")
|
||||
end
|
||||
|
@ -160,7 +166,7 @@ function mp:err(err)
|
|||
pr (mp:mesg 'MULTIPLE', " ", self.multi[1])
|
||||
for k = 2, #self.multi do
|
||||
if k == #self.multi then
|
||||
pr (" ", mp.msg.HINT_AND, " ", self.multi[k])
|
||||
pr (" ", mp.msg.AND, " ", self.multi[k])
|
||||
else
|
||||
pr (", ", self.multi[k])
|
||||
end
|
||||
|
@ -234,11 +240,11 @@ mp.door = std.class({
|
|||
end;
|
||||
}, std.obj):attr 'enterable,openable,door'
|
||||
|
||||
local function pnoun(noun, m, ...)
|
||||
function mp:pnoun(noun, msg)
|
||||
local ctx = mp:save_ctx()
|
||||
mp.first = noun
|
||||
mp.first_hint = noun:gram().hint
|
||||
mp:message(m, ...)
|
||||
std.p(mp.fmt(msg)) -- first is available only here, so fmt is forced
|
||||
mp:restore_ctx(ctx)
|
||||
end
|
||||
|
||||
|
@ -460,8 +466,8 @@ std.player.look = function(s)
|
|||
if s:need_scene() then
|
||||
scene = r:scene()
|
||||
end
|
||||
return (std.par(std.scene_delim, scene or false, r:display() or false))
|
||||
end;
|
||||
return (std.par(std.scene_delim, scene or false, r:display() or false, std.call(mp, 'footer') or false))
|
||||
end
|
||||
|
||||
--
|
||||
local function check_persist(w)
|
||||
|
@ -604,9 +610,8 @@ end
|
|||
-- dialogs
|
||||
std.phr.raw_word = function(s)
|
||||
local dsc = std.call(s, 'dsc')
|
||||
if (dsc == nil) then
|
||||
error("Phrase without dsc", 2)
|
||||
dsc = ''
|
||||
if type(dsc) ~= 'string' then
|
||||
std.err("Empty dsc in phrase", 2)
|
||||
end
|
||||
return dsc .. '|'.. (tostring(s.__ph_idx) or std.dispof(s))
|
||||
end
|
||||
|
@ -761,16 +766,64 @@ mp.compass_dir = function(_, w, dir)
|
|||
return w ^ ('@'..dir)
|
||||
end
|
||||
|
||||
mp.msg.INFODSC = function(o)
|
||||
return mp:infodsc(o)
|
||||
end
|
||||
|
||||
mp.detailed_attr = {
|
||||
{ 'worn' },
|
||||
{ 'open', 'openable'},
|
||||
-- { 'on', 'switchable'},
|
||||
-- { 'light' }
|
||||
}
|
||||
|
||||
function mp:infodsc(ob)
|
||||
local info = {}
|
||||
for _, v in ipairs(self.detailed_attr) do
|
||||
local hit = #v > 0
|
||||
for _, vv in ipairs(v) do
|
||||
if ob:hasnt(vv) then
|
||||
hit = false
|
||||
break
|
||||
end
|
||||
end
|
||||
if hit then
|
||||
local n = 'HAS_'..string.upper(v[1])
|
||||
if mp.msg[n] then
|
||||
table.insert(info, mp:mesg(n, ob))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if #info > 0 then
|
||||
pr(" (")
|
||||
for k, i in ipairs(info) do
|
||||
if #info > 1 and k == #info then
|
||||
pr(' ', mp.msg.AND, ' ')
|
||||
elseif k > 1 then
|
||||
pr(", ")
|
||||
end
|
||||
pr(i)
|
||||
end
|
||||
pr(")")
|
||||
end
|
||||
end
|
||||
|
||||
function mp:multidsc(oo, inv)
|
||||
local t = {}
|
||||
local dup = {}
|
||||
local hint = type(inv) == 'string' and inv or ''
|
||||
for _, v in ipairs(oo) do
|
||||
local n
|
||||
if not v:has'concealed' then
|
||||
if inv then
|
||||
if inv == true then
|
||||
n = std.call(v, 'inv')
|
||||
end
|
||||
n = n or v:noun(1)
|
||||
if type(v.a_noun) == 'function' then
|
||||
n = n or v:a_noun(hint, 1)
|
||||
else
|
||||
n = n or v:noun(hint, 1)
|
||||
end
|
||||
if dup[n] then
|
||||
dup[n] = dup[n] + 1
|
||||
else
|
||||
|
@ -790,17 +843,20 @@ function mp:multidsc(oo, inv)
|
|||
end
|
||||
end
|
||||
if dup[v] > 1 then
|
||||
pr (vv.ob:noun(self.mrd.lang.gram_t.plural, 1), " (", dup[v], " ", mp.msg.ENUM, ")")
|
||||
pr (ob:noun(hint .. ','..self.mrd.lang.gram_t.plural, 1), " (", dup[v], " ", mp:mesg('ENUM', dup[v], ob), ")")
|
||||
else
|
||||
pr (v)
|
||||
if ob:has'worn' then
|
||||
pr(mp:mesg('WORN', ob))
|
||||
elseif ob:has'openable' and ob:has'open' then
|
||||
pr(mp:mesg('OPEN', ob))
|
||||
pr(mp:mesg('INFODSC', ob))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Default priority in content
|
||||
function mp:defpri(w)
|
||||
if mp:animate(w) then
|
||||
return -1
|
||||
end
|
||||
p "."
|
||||
return 0
|
||||
end
|
||||
|
||||
mp.msg.Exam = {}
|
||||
|
@ -842,8 +898,8 @@ function mp:content(w, exam)
|
|||
self:objects(self.persistent, oo, false)
|
||||
end
|
||||
std.sort(oo, function (a, b)
|
||||
a = std.tonum(a.pri) or 0
|
||||
b = std.tonum(b.pri) or 0
|
||||
a = std.tonum(a.pri) or mp:defpri(a)
|
||||
b = std.tonum(b.pri) or mp:defpri(b)
|
||||
if a == b then
|
||||
return nil
|
||||
end
|
||||
|
@ -895,38 +951,10 @@ function mp:content(w, exam)
|
|||
oo = ooo
|
||||
if #oo == 0 then
|
||||
if not inside and exam and mp.first == w and not something then
|
||||
if w:has 'supporter' then
|
||||
pnoun (w, 'Exam.ON')
|
||||
else
|
||||
pnoun (w, 'Exam.IN')
|
||||
mp:message ('Exam.NOTHING', w)
|
||||
end
|
||||
mp:message 'Exam.NOTHING'
|
||||
end
|
||||
elseif #oo == 1 and not oo[1]:hint 'plural' then
|
||||
if std.me():where() == w or std.here() == w then
|
||||
mp:message('Look.HEREIS', w)
|
||||
else
|
||||
if w:has 'supporter' then
|
||||
pnoun (w, 'Exam.ON')
|
||||
else
|
||||
pnoun (w, 'Exam.IN')
|
||||
end
|
||||
mp:message 'Exam.IS'
|
||||
end
|
||||
-- p(oo[1]:noun(1), ".")
|
||||
mp:multidsc(oo)
|
||||
else
|
||||
if std.me():where() == w or std.here() == w then
|
||||
mp:message('Look.HEREARE', w)
|
||||
else
|
||||
if w:has 'supporter' then
|
||||
pnoun (w, 'Exam.ON')
|
||||
else
|
||||
pnoun (w, 'Exam.IN')
|
||||
end
|
||||
mp:message 'Exam.ARE'
|
||||
end
|
||||
mp:multidsc(oo)
|
||||
mp:message('Exam.CONTENT', w, oo)
|
||||
end
|
||||
-- expand?
|
||||
for _, o in ipairs(expand) do
|
||||
|
@ -938,6 +966,14 @@ end
|
|||
|
||||
std.room:attr 'enterable,light'
|
||||
|
||||
function mp:strip(r)
|
||||
if std.strip_call and type(r) == 'string' then
|
||||
r = r:gsub("^[%^\n\r\t ]+", "") -- extra heading ^ and spaces
|
||||
r = r:gsub("[%^\n\r\t ]+$", "") -- extra trailing ^ and spaces
|
||||
end
|
||||
return r
|
||||
end
|
||||
|
||||
function mp:step()
|
||||
local old_daemons = {}
|
||||
game.__daemons:for_each(function(o)
|
||||
|
@ -960,32 +996,31 @@ function mp:step()
|
|||
end
|
||||
end
|
||||
local s = std.game -- after reset game is recreated
|
||||
local r = std.pget()
|
||||
if std.strip_call and type(r) == 'string' then
|
||||
r = r:gsub("^[%^\n\r\t ]+", "") -- extra heading ^ and spaces
|
||||
r = r:gsub("[%^\n\r\t ]+$", "") -- extra trailing ^ and spaces
|
||||
end
|
||||
local r = mp:strip(std.pget())
|
||||
s:reaction(r or false)
|
||||
std.pclr()
|
||||
s:step()
|
||||
r = s:display(true)
|
||||
if std.strip_call and type(r) == 'string' then
|
||||
r = r:gsub("^[%^\n\r\t ]+", "") -- extra heading ^ and spaces
|
||||
r = r:gsub("[%^\n\r\t ]+$", "") -- extra trailing ^ and spaces
|
||||
end
|
||||
r = mp:strip(s:display(true))
|
||||
s:lastreact(s:reaction() or false)
|
||||
s:lastdisp(r)
|
||||
std.pr(r)
|
||||
std.abort_cmd = true
|
||||
end
|
||||
|
||||
local last_gfx = false
|
||||
function mp:post_action()
|
||||
if self:noparser() or
|
||||
(self.event and self.event:find("Meta", 1, true)) or
|
||||
self:comment() then
|
||||
if not std.abort_cmd then
|
||||
game:time(game:time() - 1)
|
||||
if (self.event and self.event:find("Meta", 1, true)) or self:comment() or self:noparser() then
|
||||
if std.abort_cmd then
|
||||
return
|
||||
end
|
||||
local s = std.game
|
||||
local r = mp:strip(std.pget())
|
||||
s:reaction(r or false)
|
||||
std.pclr()
|
||||
r = mp:strip(s:display(self:noparser()))
|
||||
s:lastdisp(r)
|
||||
s:lastreact(s:reaction() or false)
|
||||
std.pr(r)
|
||||
std.abort_cmd = true
|
||||
return
|
||||
end
|
||||
if mp.undo > 0 then
|
||||
|
@ -1011,8 +1046,9 @@ function mp:post_action()
|
|||
if not gfx and std.game.gfx ~= nil then
|
||||
gfx = std.call(std.game, 'gfx')
|
||||
end
|
||||
if gfx then
|
||||
if gfx and gfx ~= last_gfx then
|
||||
pn(fmt.c(fmt.img(gfx)))
|
||||
last_gfx = gfx
|
||||
end
|
||||
p(l, std.scene_delim)
|
||||
game.player:need_scene(false)
|
||||
|
@ -1277,11 +1313,7 @@ function mp:detailed_Inv(wh, indent)
|
|||
for _ = 1, indent do pr(iface:nb' ') end
|
||||
local inv = std.call(o, 'inv') or o:noun(1)
|
||||
pr(inv)
|
||||
if o:has'worn' then
|
||||
mp:message('WORN', o)
|
||||
elseif o:has'openable' and o:has'open' then
|
||||
mp:message('OPEN', o)
|
||||
end
|
||||
mp:message('INFODSC', o)
|
||||
pn()
|
||||
if o:has'supporter' or o:has'container' then
|
||||
mp:detailed_Inv(o, indent + 1)
|
||||
|
@ -1312,6 +1344,7 @@ function mp:after_Inv()
|
|||
else
|
||||
p()
|
||||
mp:multidsc(oo, true)
|
||||
p "."
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -1382,7 +1415,7 @@ function mp:mesg(m, ...)
|
|||
for _, n in ipairs(t) do
|
||||
m = m[n]
|
||||
if not m then
|
||||
std.err("Wrong message id", 2)
|
||||
std.err("Wrong message id: "..tostring(n), 2)
|
||||
end
|
||||
end
|
||||
if type(m) ~= 'function' then
|
||||
|
@ -1713,6 +1746,10 @@ function mp:Remove(w, wh)
|
|||
mp:message 'Remove.WHERE'
|
||||
return
|
||||
end
|
||||
if wh == std.me() then
|
||||
mp:xaction('Disrobe', w, wh)
|
||||
return
|
||||
end
|
||||
mp:xaction('Take', w, wh)
|
||||
end
|
||||
|
||||
|
@ -2772,6 +2809,11 @@ function mp:MetaHelp()
|
|||
pn(mp:mesg 'HELP')
|
||||
end
|
||||
|
||||
function mp:MetaScore()
|
||||
mp:message'TITLE_TURNS'
|
||||
mp:message'TITLE_SCORE'
|
||||
end
|
||||
|
||||
function mp:MetaTranscript()
|
||||
if self.logfile then
|
||||
p("Log file: ", self.logfile)
|
||||
|
@ -2801,6 +2843,21 @@ function mp:MetaTranscriptOn()
|
|||
self.lognum = self.lognum + 1
|
||||
end
|
||||
end
|
||||
function mp:MetaVersion()
|
||||
p(mp.version)
|
||||
end
|
||||
function mp:MetaVerbs()
|
||||
local verbs = {}
|
||||
for _, v in ipairs(mp:verbs()) do
|
||||
local vv = v.verb[1]
|
||||
if vv and not vv.hidden then
|
||||
local verb = vv.word .. (vv.morph or "")
|
||||
table.insert(verbs, verb)
|
||||
end
|
||||
end
|
||||
table.sort(verbs)
|
||||
for _, v in ipairs(verbs) do p(v) end
|
||||
end
|
||||
|
||||
mp.msg.MetaRestart = {}
|
||||
|
||||
|
@ -3080,13 +3137,14 @@ instead.get_title = function(_)
|
|||
local col = instead.theme_var('win.col.fg')
|
||||
local score = ''
|
||||
if mp.score then
|
||||
score = fmt.tab('70%', 'center')..fmt.nb(mp:mesg('TITLE_SCORE') .. tostring(mp.score))
|
||||
score = fmt.tab('70%', 'center')..fmt.nb(mp:mesg('TITLE_SCORE'))
|
||||
end
|
||||
local moves = fmt.tab('100%', 'right')..fmt.nb(mp:mesg('TITLE_TURNS') .. tostring(game:time() - 1))
|
||||
local moves = fmt.tab('100%', 'right')..fmt.nb(mp:mesg('TITLE_TURNS'))
|
||||
return iface:left((title.. score .. moves).."\n".. iface:img(string.format("box:%dx1,%s", w, col)))
|
||||
end
|
||||
|
||||
--luacheck: globals content
|
||||
function content(...)
|
||||
return mp:content(...)
|
||||
function content(w, ...)
|
||||
w = std.object(w)
|
||||
return mp:content(w, ...)
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue