Defines.fs 79 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260
  1. module Qsp.Defines
  2. module Tools =
  3. open FParsec
  4. type 'a Parser = Parser<'a, unit>
  5. let removeEmptyLines () =
  6. Clipboard.getSet (fun str ->
  7. // let x = System.Text.RegularExpressions.Regex.Replace(str, "^\n", "", System.Text.RegularExpressions.RegexOptions.Multiline)
  8. // x
  9. let ws = manySatisfy (fun c -> System.Char.IsWhiteSpace c && c <> '\n')
  10. let wsLine = ws .>>? skipNewline
  11. let p =
  12. spaces
  13. >>. many
  14. (
  15. ws >>. many1Satisfy ((<>) '\n')
  16. .>> (skipNewline <|> eof)
  17. .>> many wsLine
  18. )
  19. |>> String.concat "\n"
  20. match run p str with
  21. | Success(x, _, _) -> x
  22. | Failure(x, _, _) -> failwithf "%A" x
  23. )
  24. // removeEmptyLines()
  25. module Show =
  26. open FsharpMyExtension
  27. open FsharpMyExtension.ShowList
  28. let print tabsCount isFunction xs =
  29. let tab = replicate 4 ' '
  30. let showStr x =
  31. showAutoParen "\""
  32. (showString
  33. (x
  34. |> String.collect (
  35. function
  36. | '"' -> "\\\""
  37. | '\\' -> "\\\\"
  38. | x -> string x )))
  39. xs
  40. |> List.collect (fun (descs, varName) ->
  41. let desc =
  42. [
  43. yield showChar '['
  44. yield!
  45. descs
  46. |> List.map (fun x ->
  47. tab << showStr x)
  48. yield showChar ']' << showString " |> String.concat \"\\n\""
  49. ]
  50. [
  51. yield showString "let dscr ="
  52. yield! List.map ((<<) tab) desc
  53. let signature =
  54. if isFunction then
  55. showString ", " << showString "failwith \"not implemented\""
  56. else
  57. empty
  58. yield
  59. showAutoParen "\"" (showString varName) << showString ", " << showString "dscr"
  60. << signature
  61. ]
  62. )
  63. |> List.map ((<<) (showReplicate tabsCount tab))
  64. |> joinEmpty "\n"
  65. |> show
  66. let parse tabsCount isFunction =
  67. Clipboard.getSet (fun str ->
  68. let description =
  69. many1
  70. (pstring "///" >>. optional (skipChar ' ') >>. manySatisfy ((<>) '\n') .>> spaces)
  71. let expr =
  72. between
  73. (skipChar '"')
  74. (skipChar '"')
  75. (manySatisfy ((<>) '"'))
  76. let p = spaces >>. many (description .>>. expr .>> spaces)
  77. match run (p .>> eof) str with
  78. | Success(xs, _, _) -> Show.print tabsCount isFunction xs
  79. | Failure(x, _, _) -> failwithf "%A" x
  80. )
  81. // parse 2 true
  82. [<Struct>]
  83. type VarType =
  84. | Any
  85. | String
  86. | Numeric
  87. // type X () =
  88. // member __.F(x:string, [<System.ParamArray>] args: string[]) =
  89. // printfn "first"
  90. // for arg in args do
  91. // printfn "%A" arg
  92. // member __.F(x:string, y:string, [<System.ParamArray>] args: string[]) =
  93. // printfn "second"
  94. // for arg in args do
  95. // printfn "%A" arg
  96. // let x = X()
  97. // x.F("1")
  98. // x.F("1", y = "2")
  99. // x.F("1", y = "2", "3")
  100. type 'Func OverloadType =
  101. | JustOverloads of (VarType [] * 'Func) list
  102. /// Если говорить родным F#, то это:
  103. /// ```fsharp
  104. /// member __.F(x:Type1, y:Type2, [&lt;System.ParamArray>] args: Type3 []) =
  105. /// ```
  106. /// выражается так:
  107. /// ```fsharp
  108. /// {| Requireds: [ Type1; Type2 ]; ArgList: Type3 |}
  109. /// ```
  110. | ParamArrayOverload of {| Requireds: VarType []; ArgList: VarType |} * 'Func
  111. module Show =
  112. open FsharpMyExtension.ShowList
  113. let showVarType = function
  114. | Any -> showString "any"
  115. | String -> showString "string"
  116. | Numeric -> showString "numeric"
  117. let showParamArray typ =
  118. // На Lua:
  119. // ```lua
  120. // function f(...)
  121. // -- ...
  122. // end
  123. // ```
  124. // В Python:
  125. // ```python
  126. // def my_function(*argName):
  127. // # ...
  128. // ```
  129. // Но это то, как оно объявляется, а сигнатуру-то как написать?
  130. // showChar '*' << showChar ':' << showVarType typ
  131. showVarType typ << showSpace << showString "[]"
  132. let showArgs varTypes =
  133. varTypes
  134. |> Array.map showVarType
  135. |> List.ofArray
  136. |> joins (showChar ',' << showSpace)
  137. let printSignature (name:string) =
  138. function
  139. | JustOverloads xs ->
  140. xs
  141. |> List.map (fun (varTypes, _) ->
  142. showString name << showParen true (showArgs varTypes)
  143. )
  144. |> lines
  145. | ParamArrayOverload(x, _) ->
  146. showString name
  147. << showParen true
  148. (showArgs x.Requireds << showChar ',' << showSpace
  149. << showParamArray x.ArgList)
  150. >> show
  151. let printFuncSignature (name:string) (returnType:VarType) =
  152. function
  153. | JustOverloads xs ->
  154. xs
  155. |> List.map (fun (varTypes, _) ->
  156. showString name << showParen true (showArgs varTypes)
  157. << showChar ':' << showSpace << showVarType returnType
  158. )
  159. |> lines
  160. | ParamArrayOverload(x, _) ->
  161. showString name
  162. << showParen true
  163. (showArgs x.Requireds << showChar ',' << showSpace
  164. << showParamArray x.ArgList)
  165. << showChar ':' << showSpace << showVarType returnType
  166. >> show
  167. let getFuncByOverloadType overloadType (inputArgs: _ []) =
  168. let inputArgsLength = Array.length inputArgs
  169. match overloadType with
  170. | JustOverloads os ->
  171. os
  172. |> List.tryPick (fun (x, func) ->
  173. if x.Length = inputArgsLength then
  174. Some func
  175. else None
  176. )
  177. | ParamArrayOverload(x, func) ->
  178. if inputArgsLength < x.Requireds.Length then
  179. None
  180. else
  181. Some func
  182. let arg x =
  183. [[|x|] , ()] |> JustOverloads
  184. let unit' =
  185. [[||] , ()] |> JustOverloads
  186. let args xs =
  187. [xs |> Array.ofList, ()] |> JustOverloads
  188. let argsAndOptional xs opt =
  189. [
  190. xs |> Array.ofList, ()
  191. xs @ [opt] |> Array.ofList, ()
  192. ] |> JustOverloads
  193. let argList typ =
  194. ({| Requireds = [||]; ArgList = typ |}, ())
  195. |> ParamArrayOverload
  196. let argAndArgList x typ =
  197. ({| Requireds = [|x|]; ArgList = typ |}, ())
  198. |> ParamArrayOverload
  199. type VarName = string
  200. type Description = string
  201. let proceduresWithAsterix =
  202. [
  203. let dscr =
  204. [
  205. "`*CLEAR` или `*CLR` - очистка основного окна описаний."
  206. ] |> String.concat "\n"
  207. ("*clear":VarName), (dscr:Description), unit'
  208. let dscr =
  209. [
  210. "`*CLEAR` или `*CLR` - очистка основного окна описаний."
  211. ] |> String.concat "\n"
  212. "*clr", dscr, unit'
  213. let dscr =
  214. [
  215. "`*NL [выражение]` - переход на новую строку, затем вывод текста в основном окне описаний. Если `[выражение]` не указано, то перевод строки. Отличается от *PL порядком вывода текста."
  216. ] |> String.concat "\n"
  217. let funcs =
  218. [
  219. [| String |], ()
  220. [| |], ()
  221. ] |> JustOverloads
  222. "*nl", dscr, funcs
  223. let dscr =
  224. [
  225. "`*P [выражение]` - вывод текста в основное окно описаний (по умолчанию находится слева сверху и не может быть отключено)."
  226. ]|> String.concat "\n"
  227. "*p", dscr, arg Any
  228. let dscr =
  229. [
  230. "`*PL [выражение]` - вывод текста, затем переход на новую строку в основном окне описаний. Если `[выражение]` не указано, то перевод строки. Аналогичным образом можно вывести текст, просто написав нужное выражение вместо данного оператора. Например, строки:"
  231. "```qsp"
  232. "*PL $AAA+'989'"
  233. "*PL 'Вы находитесь в парке'"
  234. "*PL 'Преформатированная"
  235. "строка'"
  236. "```"
  237. "и"
  238. "```qsp"
  239. "$AAA+'989'"
  240. "'Вы находитесь в парке'"
  241. "'Преформатированная"
  242. "строка'"
  243. "```"
  244. "выполнят одно и то же действие."
  245. ] |> String.concat "\n"
  246. let funcs =
  247. [
  248. [| String |], ()
  249. [| |], ()
  250. ] |> JustOverloads
  251. "*pl", dscr, funcs
  252. ]
  253. |> List.map (fun (name, dscr, sign) -> name, (dscr, sign))
  254. |> Map.ofList
  255. /// Заданные переменные
  256. let vars =
  257. [
  258. let dscr =
  259. [
  260. "содержит путь к файлу изображения локации. Изображение локации показывается в том случае, если значение данной переменной отлично от '' (не пустая строка) и файл изображения удалось загрузить."
  261. ] |> String.concat "\n"
  262. ("$backimage":VarName), (dscr:Description)
  263. let dscr =
  264. [
  265. "Название выделенного действия."
  266. ] |> String.concat "\n"
  267. "$selact", dscr
  268. let dscr =
  269. [
  270. "содержит название локации-счётчика. Локация-счётчик полезна для проверки выделенных предметов, введённого текста..."
  271. ] |> String.concat "\n"
  272. "$counter", dscr
  273. let dscr =
  274. [
  275. "текущие действия в виде текста. Сохранив значение в переменной, восстановить действия можно в любой момент игры с помощью оператора `DYNAMIC`."
  276. ] |> String.concat "\n"
  277. "$curacts", dscr
  278. let dscr =
  279. [
  280. "текст, находящийся в основном окне описаний. Также есть функция `maintxt`"
  281. ] |> String.concat "\n"
  282. "$maintxt", dscr
  283. let dscr =
  284. [
  285. "содержит название используемого в данный момент шрифта. Если равна '' (пустая строка), то используется шрифт, заданный в настройках программы."
  286. ] |> String.concat "\n"
  287. "$fname", dscr
  288. let dscr =
  289. [
  290. "содержит название локации-обработчика выбора действия. Данная локация полезна, к примеру, для вывода изображений или проигрывания звуков при выборе действий. Получить название выбранного действия можно через функцию `SELACT`."
  291. ] |> String.concat "\n"
  292. "$onactsel", dscr
  293. let dscr =
  294. [
  295. "содержит название локации-обработчика загрузки состояния. Данная локация полезна для выполнения каких-либо действий после загрузки состояния игры."
  296. ] |> String.concat "\n"
  297. "$ongload", dscr
  298. let dscr =
  299. [
  300. "содержит название локации-обработчика сохранения состояния. Данная локация полезна для выполнения каких-либо действий перед сохранением состояния игры."
  301. ] |> String.concat "\n"
  302. "$ongsave", dscr
  303. let dscr =
  304. [
  305. "содержит название локации-обработчика перехода на новую локацию (аналог локации \"common\" в URQ). Может заменить часть функций локации-счётчика. Получить название локации, на которую был осуществлён переход, можно с помощью функции `CURLOC`."
  306. ] |> String.concat "\n"
  307. "$onnewloc", dscr
  308. let dscr =
  309. [
  310. "содержит название локации-обработчика добавления предмета. При добавлении предмета локация вызывается с аргументом `$ARGS[0]` - названием добавленного предмета. Данная локация полезна, к примеру, для ограничения вместительности рюкзака."
  311. ] |> String.concat "\n"
  312. "$onobjadd", dscr
  313. let dscr =
  314. [
  315. "содержит название локации-обработчика удаления предмета. При удалении предмета локация вызывается с аргументом `$ARGS[0]` - названием удалённого предмета. Данная локация полезна, к примеру, для проверки возможности удаления предмета."
  316. ] |> String.concat "\n"
  317. "$onobjdel", dscr
  318. let dscr =
  319. [
  320. "содержит название локации-обработчика выбора предмета. Данная локация полезна, к примеру, для вывода меню предметов. Получить название выбранного предмета можно через функцию `SELOBJ`."
  321. ] |> String.concat "\n"
  322. "$onobjsel", dscr
  323. let dscr =
  324. [
  325. "текст, находящийся в окне пользователя. Также есть функция `stattxt`"
  326. ] |> String.concat "\n"
  327. "$stattxt", dscr
  328. let dscr =
  329. [
  330. "содержит название локации-обработчика строки ввода. Полезна при организации парсера (управление игрой с помощью строки ввода). Текущий текст строки ввода возвращает функция `USER_TEXT`."
  331. ] |> String.concat "\n"
  332. "$usercom", dscr
  333. let dscr =
  334. [
  335. "название текущей локации, также можно использовать `curloc`"
  336. ] |> String.concat "\n"
  337. "$curloc", dscr
  338. let dscr =
  339. [
  340. "содержит размер используемого в данный момент шрифта. Если равна 0, то используется размер, заданный в настройках программы. Относительно данного значения в HTML-режиме вычисляются размеры шрифтов тега \"FONT\"."
  341. ] |> String.concat "\n"
  342. "fsize", dscr
  343. let dscr =
  344. [
  345. "содержит цвет текущего фона. Если равна 0, то используется цвет, заданный в настройках программы."
  346. ] |> String.concat "\n"
  347. "bcolor", dscr
  348. let dscr =
  349. [
  350. "содержит цвет используемого в данный момент шрифта. Если равна 0, то используется цвет, заданный в настройках программы."
  351. ] |> String.concat "\n"
  352. "fcolor", dscr
  353. let dscr =
  354. [
  355. "содержит текущий цвет ссылок. Если равна 0, то используется цвет, заданный в настройках программы."
  356. ] |> String.concat "\n"
  357. "lcolor", dscr
  358. let dscr =
  359. [
  360. "если отлична от 0, включает возможность использования HTML в описании локации, в дополнительном описании, в списках действий и предметов, а также в диалоге ввода текста, вызываемого функцией `INPUT`. Выводимый текст распознаётся как HTML. Список поддерживаемых тегов и их атрибутов смотрите в приложении."
  361. ] |> String.concat "\n"
  362. "usehtml", dscr
  363. let dscr =
  364. [
  365. "Массив, который содержит аргументы текущей локации. Подробнее расписано в процедуре `GOSUB` и ей подобной."
  366. ] |> String.concat "\n"
  367. "args", dscr
  368. "#args", dscr
  369. "$args", dscr
  370. let dscr =
  371. "Если текущая локация вызвана с помощью `FUNC` или создана динамически с помощью `DYNEVAL`, то по итогу вернется это значение. Ах да, эта переменная бывает нескольких типов: `result`, `#result` и `$result`. И возникает вопрос: а что, собственно, вернет, скажем, вызов `DYNEVAL(\"$result = 'string' & #result = 1\")`? Что ж, сработает только `$x = DYNEVAL(\"$result = 'string' & #result = 1\") & $x`, а `#x = DYNEVAL(\"$result = 'string' & #result = 1\") & #x` — выбьет ошибку про несоответствие данных, что довольно странно."
  372. "result", dscr
  373. "$result", dscr
  374. "#result", dscr
  375. let dscr =
  376. [
  377. "если значение переменной не равно 0, то отключается проверка идентификатора игры при загрузке состояния. Полезно для отладки."
  378. ] |> String.concat "\n"
  379. "debug", dscr
  380. let dscr =
  381. [
  382. "если значение переменной не равно 0, то запрещает автопрокрутку текста при его выводе в основное или дополнительное окно описания локации."
  383. ] |> String.concat "\n"
  384. "disablescroll", dscr
  385. let dscr =
  386. [
  387. "если значение переменной не равно 0, то запрещает использование \"подвыражений\" в тексте (например, значением `'<<5+6>>'` будет строка `'<<5+6>>'`, а не `'11'`)."
  388. ] |> String.concat "\n"
  389. "disablesubex", dscr
  390. let dscr =
  391. [
  392. "Если её значение отлично от 0, то сохранение состояния игры пользователем невозможно."
  393. ] |> String.concat "\n"
  394. "nosave", dscr
  395. ]
  396. |> Map.ofList
  397. [<Struct>]
  398. type PredefFunc =
  399. | Arrcomp
  400. | Arrpos
  401. | Arrsize
  402. | Countobj
  403. | Curacts
  404. | Curloc
  405. | Desc
  406. | Dyneval
  407. | Func
  408. | Getobj
  409. | Iif
  410. | Input
  411. | Instr
  412. | Isnum
  413. | Isplay
  414. | Lcase
  415. | Len
  416. | Maintxt
  417. | Max
  418. | Mid
  419. | Min
  420. | Msecscount
  421. | Qspver
  422. | Rand
  423. | Replace
  424. | Rgb
  425. | Rnd
  426. | Selact
  427. | Selobj
  428. | Stattxt
  429. | Str
  430. | Strcomp
  431. | Strfind
  432. | Strpos
  433. | Trim
  434. | Ucase
  435. | User_text
  436. | Usrtxt
  437. | Val
  438. let functions =
  439. let arg x (return':VarType) = arg x, return'
  440. let unit' (return':VarType) = unit', return'
  441. let args xs (return':VarType) = args xs, return'
  442. let argList typ (return':VarType) = argList typ, return'
  443. let argAndArgList x typ (return':VarType) = argAndArgList x typ, return'
  444. [
  445. let dscr =
  446. [
  447. "`RAND([#выражение 1],[#выражение 2])` - возвращает случайное число между числами `[#выражение 1]` и `[#выражение 2]`. Параметр `[#выражение 2]` может отсутствовать, при этом он принимается равным 0."
  448. ] |> String.concat "\n"
  449. let os =
  450. [
  451. [| Numeric; Numeric |], ()
  452. [| Numeric |], ()
  453. ] |> JustOverloads
  454. Rand, dscr, (os, Numeric)
  455. let dscr =
  456. [
  457. "возвращает название текущей локации, также можно использовать переменную `$curloc`"
  458. ] |> String.concat "\n"
  459. Curloc, dscr, unit' String
  460. let dscr =
  461. [
  462. "возвращает случайное значение от 1 до 1000."
  463. ] |> String.concat "\n"
  464. Rnd, dscr, unit' Numeric
  465. let dscr =
  466. [
  467. "`INPUT([$выражение])` - выводит окно ввода с приглашением [$выражение]. Возвращает введённый играющим текст, либо '' (пустая строка), если была нажата кнопка \"Отмена\"."
  468. ] |> String.concat "\n"
  469. Input, dscr, arg String String
  470. let dscr =
  471. [
  472. "возвращает текст, находящийся в строке ввода. Синоним `usrtxt`"
  473. ] |> String.concat "\n"
  474. User_text, dscr, unit' String
  475. let dscr =
  476. [
  477. "возвращает текст, находящийся в строке ввода. Синоним `user_text`"
  478. ] |> String.concat "\n"
  479. Usrtxt, dscr, unit' String
  480. let dscr =
  481. [
  482. "`MAX([выражение 1],[выражение 2], ...)` - возвращает максимальное из значений выражений-аргументов. Если передан один аргумент, то считается, что указано имя массива - в этом случае поиск максимального элемента происходит среди строковых (если название массива указано со знаком \"$\") или среди числовых значений элементов массива. Например:"
  483. "```qsp"
  484. "MAX(1,2,5,2,0) & ! вернёт 5"
  485. "MAX(a,b,c) & ! вернёт максимальное из значений переменных"
  486. "MAX('aa','ab','zz') & ! вернёт 'zz'"
  487. "MAX('a') & ! вернёт максимальное из числовых значений элементов массива \"A\""
  488. "MAX('$b') & ! вернёт максимальное из строковых значений элементов массива \"B\""
  489. "```"
  490. ] |> String.concat "\n"
  491. Max, dscr, argList Any Any
  492. let dscr =
  493. [
  494. "`MIN([выражение 1],[выражение 2], ...)` - возвращает минимальное из значений выражений-аргументов. Если передан один аргумент, то считается, что указано имя массива - в этом случае поиск минимального элемента происходит среди строковых (если название массива указано со знаком \"$\") или среди числовых значений элементов массива."
  495. ] |> String.concat "\n"
  496. Min, dscr, argList Any Any
  497. let dscr =
  498. [
  499. "`IIF([#выражение],[выражение_да],[выражение_нет])` - возвращает значение выражения [выражение_да], если [#выражение] верно, иначе значение выражения [выражение_нет]."
  500. ] |> String.concat "\n"
  501. Iif, dscr, args [Numeric; Any; Any] Any
  502. let dscr =
  503. [
  504. "`RGB([#выражение 1],[#выражение 2],[#выражение 3])` - возвращает код цвета на основе 3-х числовых аргументов. [#выражение 1], [#выражение 2] и [#выражение 3] определяют соответственно уровни красного, зелёного и синего цветов. Все значения аргументов должны быть в отрезке [0, 255]. Данная функция используется совместно с системными переменными `BCOLOR`, `FCOLOR` и `LCOLOR`."
  505. ] |> String.concat "\n"
  506. Rgb, dscr, args [Numeric; Numeric; Numeric] Numeric
  507. let dscr =
  508. [
  509. "`ISPLAY([$выражение])` - проверяет, проигрывается ли файл с заданным названием в текущий момент времени и возвращает -1, если файл воспроизводится, иначе 0."
  510. ] |> String.concat "\n"
  511. Isplay, dscr, arg String Numeric
  512. let dscr =
  513. [
  514. "возвращает количество миллисекунд, прошедших с момента начала игры."
  515. ] |> String.concat "\n"
  516. Msecscount, dscr, unit' Numeric
  517. let dscr =
  518. [
  519. "`DESC([$выражение])` - возвращает текст базового описания локации с заданным в [$выражение] названием."
  520. ] |> String.concat "\n"
  521. Desc, dscr, arg String String
  522. let dscr =
  523. [
  524. "возвращает текст, находящийся в основном окне описаний. Также есть переменная `$maintxt`"
  525. ] |> String.concat "\n"
  526. Maintxt, dscr, unit' String
  527. let dscr =
  528. [
  529. "возвращает текст, находящийся в окне пользователя. Также есть переменная `$stattxt`"
  530. ] |> String.concat "\n"
  531. Stattxt, dscr, unit' String
  532. let dscr =
  533. [
  534. "возвращает версию интерпретатора в формате \"X.Y.Z\""
  535. ] |> String.concat "\n"
  536. Qspver, dscr, unit' String
  537. let dscr =
  538. [
  539. "`FUNC([$выражение],[параметр 1],[параметр 2], ...)` - обработка локации с названием `[$выражение]`. Указанные параметры передаются в массиве `ARGS`. Результат функции равен значению `$RESULT` при возврате строкового значения или `RESULT` при возврате числового значения. Если при обработке локации были установлены и `RESULT`, и `$RESULT`, то предпочтение отдаётся строковому значению. После обработки локации предыдущие значения `ARGS` и `RESULT` восстанавливаются. Примеры:"
  540. "```qsp"
  541. "PL 4 + FUNC('функция') & ! обработка локации \"функция\" как функции. Массив ARGS пуст. Результат передается через `$RESULT` или `RESULT`, в зависимости от кода обрабатываемой локации."
  542. "PL FUNC($name, 1) * 78 & ! обработка локации с названием в $name как функции. `ARGS[0]` равен 1."
  543. "MSG \"text\" + FUNC($name, \"строка\", 2) & ! обработка локации с названием в $name как функции. `$ARGS[0]` содержит строку \"строка\", `ARGS[1]` равен 2."
  544. "```"
  545. "Также можно использовать `$func`:"
  546. "```qsp"
  547. "# start"
  548. "$func('toString', 1) & ! -> '1'"
  549. "-"
  550. ""
  551. "# toString"
  552. "$result = ARGS[0]"
  553. "-"
  554. "```"
  555. ] |> String.concat "\n"
  556. Func, dscr, argList Any Any
  557. let dscr =
  558. [
  559. "`DYNEVAL([$выражение],[параметр 1],[параметр 2], ...)` - возвращает значение указанного выражения. Функция позволяет вычислять значения динамически сгенерированных выражений. Указанные параметры передаются в массиве `ARGS`, а после вычисления выражения предыдущие значения `ARGS` восстанавливаются. Примеры:"
  560. "```qsp"
  561. "DYNEVAL('3+4')"
  562. "PL DYNEVAL('mid(\"abcd\",2,1)+\"qwerty\"')"
  563. "PL DYNEVAL($test + ' + val(\"<<$test>>\")')"
  564. "DYNEVAL(\" $args[0] <> 'текст' \", 'строка')"
  565. "$x = DYNEVAL(\"$result = 'текст'\") & $x"
  566. "```"
  567. ] |> String.concat "\n"
  568. Dyneval, dscr, argAndArgList String Any Any
  569. let dscr =
  570. [
  571. "возвращает количество предметов в рюкзаке."
  572. ] |> String.concat "\n"
  573. Countobj, dscr, unit' Numeric
  574. let dscr =
  575. [
  576. "возвращает название выделенного предмета."
  577. ] |> String.concat "\n"
  578. Selobj, dscr, unit' String
  579. let dscr =
  580. [
  581. "`GETOBJ([#выражение])` - возвращает название предмета в рюкзаке, расположенного в заданной позиции. Индексация предметов рюкзака ведётся с 1."
  582. "Если предмета с заданным индексом не существует, возвращается пустая строка ('')."
  583. ""
  584. "Примеры:"
  585. "```qsp"
  586. "GETOBJ(1) & ! вернёт название первого предмета в рюкзаке"
  587. "GETOBJ(COUNTOBJ) &! вернёт название последнего добавленного предмета"
  588. "```"
  589. ""
  590. "Код, подсчитывающий в массиве `OBJECTS` число предметов с одинаковым названием:"
  591. "```qsp"
  592. "i = 1"
  593. ":loop"
  594. "IF i <= COUNTOBJ:"
  595. " OBJECTS[$GETOBJ(i)] = OBJECTS[$GETOBJ(i)] + 1"
  596. " i = i + 1"
  597. " JUMP 'loop'"
  598. "END"
  599. "```"
  600. ] |> String.concat "\n"
  601. Getobj, dscr, arg Numeric String
  602. let dscr =
  603. [
  604. "`ARRCOMP([#выражение 1],[$выражение 2],[$выражение 3])` - возвращает индекс элемента массива с названием `[$выражение 2]`, соответствующего регулярному выражению `[$выражение 3]`. Поиск начинается с элемента номер `[#выражение 1]`; индексация элементов массива ведётся с нуля. Параметр `[#выражение 1]` может отсутствовать, при этом он принимается равным 0. Если элемент не найден, функция возвращает -1."
  605. "Поиск происходит среди текстовых элементов массива. Примеры:"
  606. "```qsp"
  607. "ARRCOMP(0,'A','This') & ! найдёт строку 'This' среди текстовых элементов массива \"A\" (или вернёт -1, если такого значения не существует)"
  608. "ARRCOMP(2,'A','abc\\d+') & ! найдёт строку, соответствующую регулярному выражению \"abc\\d+\", в текстовых значениях массива \"A\" (первые два элемента массива игнорируются)"
  609. "ARRCOMP(0,'A','.*string.*') & ! аналогично предыдущему примеру, но поиск осуществляется по всем текстовым элементам массива"
  610. "ARRCOMP('A','This') & ! эквивалентно 1-му варианту"
  611. "```"
  612. ] |> String.concat "\n"
  613. let funcs =
  614. [
  615. [| Numeric; String; String |], ()
  616. [| String; String |], ()
  617. ] |> JustOverloads
  618. Arrcomp, dscr, (funcs, String)
  619. let dscr =
  620. [
  621. "`STRCOMP([$выражение],[$шаблон])` - проводит сравнение строки `[$выражение]` на соответствие регулярному выражению `[$шаблон]`. Возвращает -1, если строка соответствует шаблону, иначе 0. Сравни с функцией `STRFIND`."
  622. ] |> String.concat "\n"
  623. Strcomp, dscr, args [String; String] Numeric
  624. let dscr =
  625. [
  626. "`STRFIND([$выражение],[$шаблон],[#номер])` - возвращает подстроку в строке `[$выражение]`, соответствующую группе с номером `[#номер]` регулярного выражения `[$шаблон]`. Если подстрока с указанным номером отсутствует, то возвращается пустая строка. Нумерация групп подстрок начинается с 1. Если параметр `[#номер]` отсутствует или равен 0, то возвращается подстрока, соответствующая всему регулярному выражению `[$шаблон]`. Примеры:"
  627. "```qsp"
  628. "STRFIND(' идти к пещере', '^(\\S+)\\s(\\S+)\\s(\\S+)$', 0) & ! -> ''"
  629. "STRFIND('идти к пещере', '^(\\S+)\\s(\\S+)\\s(\\S+)$', 1) & ! -> 'идти'"
  630. "STRFIND('идти к пещере', '^(\\S+)\\s(\\S+)\\s(\\S+)$', 2) & ! -> 'к'"
  631. "STRFIND('идти к пещере', '^(\\S+)\\s(\\S+)\\s(\\S+)$', 3) & ! -> 'пещере'"
  632. "STRFIND('идти к пещере', '^(\\S+)\\s(\\S+)(\\s(\\S+))?$', 4) & ! -> 'пещере'"
  633. "STRFIND('искать ключ', '^(\\S+)\\s(\\S+)(\\s(\\S+))?$', 1) & ! -> 'искать'"
  634. "STRFIND('искать', '^(\\S+)\\s(\\S+)(\\s(\\S+))?$', 0) & ! -> ''"
  635. "STRFIND('искать', '^(\\S+)\\s(\\S+)(\\s(\\S+))?$', 1) & ! -> ''"
  636. "STRFIND('искать', '^(\\S+)(\\s(\\S+)(\\s(\\S+))?)?$', 1) & ! -> 'искать'"
  637. "STRFIND('идти к дому', 'к\\s(\\S+)', 0) & ! -> 'к дому'"
  638. "STRFIND('идти к дому', 'к\\s(\\S+)') & ! -> 'к дому'"
  639. "STRFIND('идти к дому', 'к\\s(\\S+)', 1) & ! -> 'дому'"
  640. "STRFIND('идти к своему дому', 'к\\s(\\S+)', 1) & ! -> 'своему'"
  641. "```"
  642. ] |> String.concat "\n"
  643. Strfind, dscr, (argsAndOptional [ String; String ] Numeric, String)
  644. let dscr =
  645. [
  646. "`STRPOS([$выражение],[$шаблон],[#номер])` - возвращает позицию символа, с которого начинается вхождение подстроки в строке `[$выражение]`, соответствующей группе с номером `[#номер]` регулярного выражения `[$шаблон]`. Если подстрока с указанным номером отсутствует, то возвращается 0. Нумерация групп подстрок начинается с 1. Если параметр `[#номер]` отсутствует или равен 0, то возвращается позиция символа, с которого начинается вхождение подстроки, соответствующей всему регулярному выражению `[$шаблон]`."
  647. "Примеры:"
  648. "```qsp"
  649. "STRPOS(' идти к пещере', '^(\\S+)\\s(\\S+)\\s(\\S+)$', 0) & ! -> 0"
  650. "STRPOS('идти к пещере', '^(\\S+)\\s(\\S+)\\s(\\S+)$', 1) & ! -> 1"
  651. "STRPOS('идти к пещере', '^(\\S+)\\s(\\S+)\\s(\\S+)$', 2) & ! -> 6"
  652. "STRPOS('идти к пещере', '^(\\S+)\\s(\\S+)\\s(\\S+)$', 3) & ! -> 8"
  653. "STRPOS('идти к пещере', '^(\\S+)\\s(\\S+)(\\s(\\S+))?$', 4) & ! -> 8"
  654. "STRPOS('искать ключ', '^(\\S+)\\s(\\S+)(\\s(\\S+))?$', 1) & ! -> 1"
  655. "STRPOS('искать', '^(\\S+)\\s(\\S+)(\\s(\\S+))?$', 0) & ! -> 0"
  656. "STRPOS('искать', '^(\\S+)\\s(\\S+)(\\s(\\S+))?$', 1) & ! -> 0"
  657. "STRPOS('искать', '^(\\S+)(\\s(\\S+)(\\s(\\S+))?)?$', 1) & ! -> 1"
  658. "STRPOS('идти к дому', 'к\\s(\\S+)', 0) & ! -> 6"
  659. "STRPOS('идти к дому', 'к\\s(\\S+)') & ! -> 6"
  660. "STRPOS('идти к дому', 'к\\s(\\S+)', 1) & ! -> 8"
  661. "STRPOS('идти к своему дому', 'к\\s(\\S+)', 1) & ! -> 8"
  662. "```"
  663. ] |> String.concat "\n"
  664. Strpos, dscr, (argsAndOptional [ String; String ] Numeric, Numeric)
  665. let dscr =
  666. [
  667. "возвращает текущие действия в виде текста. Сохранив значение в переменной, восстановить действия можно в любой момент игры с помощью оператора `DYNAMIC`."
  668. ] |> String.concat "\n"
  669. Curacts, dscr, unit' String
  670. let dscr =
  671. [
  672. "`ARRPOS([#выражение 1],[$выражение 2],[выражение 3])` - возвращает индекс элемента массива с названием `[$выражение 2]`, равного значению выражения `[выражение 3]`. Поиск начинается с элемента номер `[#выражение 1]`; индексация элементов массива ведётся с нуля. Параметр [#выражение 1] может отсутствовать, при этом он принимается равным 0. Если указанное значение не найдено, функция возвращает -1."
  673. "Чтобы найти числовое значение в массиве, нужно в `[$выражение 2]` подставить лишь название массива (в кавычках), для строкового - название массива с символом \"$\" перед его названием. Примеры:"
  674. "`ARRPOS(0,'$A','This')` - найдёт строку 'This' в текстовых значениях массива \"A\" (или вернёт -1, если такого значения не существует)"
  675. "`ARRPOS(2,'A',65)` - найдёт число 65 в числовых значениях массива \"A\" (при этом первые два элемента массива игнорируются)"
  676. "`ARRPOS('$B','test')` - поиск строки 'test' среди текстовых значений массива \"B\""
  677. ] |> String.concat "\n"
  678. let funcs =
  679. [
  680. [| Numeric; String; Any |], ()
  681. [| String; Any |], ()
  682. ] |> JustOverloads
  683. Arrpos, dscr, (funcs, Numeric)
  684. let dscr =
  685. [
  686. "`ARRSIZE([$выражение])` - возвращает число элементов в массиве с названием `[$выражение]`."
  687. ] |> String.concat "\n"
  688. Arrsize, dscr, arg String Numeric
  689. let dscr =
  690. [
  691. "`INSTR([#выражение 1],[$выражение 2],[$выражение 3])` - возвращает номер позиции символа, с которого начинается вхождение строки `[$выражение 3]` в строку `[$выражение 2]` (или 0, если такой строки нет). Поиск начинается с символа номер `[#выражение 1]`. Параметр `[#выражение 1]` может отсутствовать, при этом он принимается равным 1. Примеры:"
  692. "`INSTR(1,'ABCDefgh','BC')` равно `2`"
  693. "`INSTR(1,'ABCDefgh','Be')` равно `0`"
  694. "`INSTR('abcdef','abc')` равно `1`"
  695. ] |> String.concat "\n"
  696. let funcs =
  697. [
  698. [| Numeric; String; String |], ()
  699. [| String; String |], ()
  700. ] |> JustOverloads
  701. Instr, dscr, (funcs, Numeric)
  702. let dscr =
  703. [
  704. "`ISNUM([$выражение])` - функция проверяет, все ли символы в строке являются цифрами (учитывая знак \"-\" в начале, прилегающие пробелы и символы табуляции). Если в указанной строке есть хотя бы один символ - не-цифра (исключая возможный \"-\" в начале и прилегающие пробелы / символы табуляции), то функция возвращает 0 (ложь), иначе -1 (истина)."
  705. "Функция полезна при проверке введённой играющим строки на число. Примеры:"
  706. "`ISNUM('9999 ')` равно `-1`"
  707. "`ISNUM(' -888')` равно `-1`"
  708. "`ISNUM('777a6')` равно `0`"
  709. ] |> String.concat "\n"
  710. Isnum, dscr, arg String Numeric
  711. let dscr =
  712. [
  713. "`LCASE([$выражение])` - возвращает строку маленьких букв, полученную изменением регистра букв исходной строки `[$выражение]`. Пример:"
  714. "```qsp"
  715. "LCASE('TExT#') & ! 'text#'"
  716. "```"
  717. ] |> String.concat "\n"
  718. Lcase, dscr, arg String String
  719. let dscr =
  720. [
  721. "`LEN([$выражение])` - возвращает длину строки `[$выражение]`."
  722. ] |> String.concat "\n"
  723. Len, dscr, arg String Numeric
  724. let dscr =
  725. [
  726. "`MID([$выражение],[#выражение 1],[#выражение 2])` - вырезает из строки `[$выражение]` строку, которая начинается с символа номер `[#выражение 1]` и имеет длину `[#выражение 2]`. Индексация символов в строке ведётся с 1."
  727. "Параметр `[#выражение 2]` может отсутствовать, при этом вырезается вся строка, начиная с символа [#выражение 1]. Примеры:"
  728. "```qsp"
  729. "MID('abcd', 1, 2) равно 'ab'"
  730. "MID('abcd', 2, 3) равно 'bcd'"
  731. "MID('abcd', 2) равно 'bcd'"
  732. "```"
  733. ] |> String.concat "\n"
  734. Mid, dscr, (argsAndOptional [ String; Numeric ] Numeric, String)
  735. let dscr =
  736. [
  737. "`REPLACE([$выражение 1],[$выражение 2],[$выражение 3])` - заменяет в строке [$выражение 1] все вхождения строки [$выражение 2] строкой [$выражение 3]. Если [$выражение 3] отсутствует или указана пустая строка, то удаляет в исходной строке все вхождения искомой строки. Примеры:"
  738. "`REPLACE('test', '12', '4')` равно `'test'`"
  739. "`REPLACE('test', 'e', 's')` равно `'tsst'`"
  740. "`REPLACE('test', 't', '34')` равно `'34es34'`"
  741. "`REPLACE('test', 't')` равно `'es'`"
  742. ] |> String.concat "\n"
  743. Replace, dscr, (argsAndOptional [ String; String ] String, String)
  744. let dscr =
  745. [
  746. "`STR([#выражение])` - переводит число (числовое выражение) `[#выражение]` в соответствующую строку. Например,"
  747. "`PL STR(56)` выведет строку `56`."
  748. ] |> String.concat "\n"
  749. Str, dscr, arg Numeric String
  750. let dscr =
  751. [
  752. "`TRIM([$выражение])` - удаляет прилегающие пробелы и символы табуляции из `[$выражение]`. Затем возвращает полученную строку. Пример:"
  753. "`TRIM(' TRIM TEST ')` равно `'TRIM TEST'`"
  754. ] |> String.concat "\n"
  755. Trim, dscr, arg String String
  756. let dscr =
  757. [
  758. "`UCASE([$выражение])` - возвращает строку больших букв, полученную изменением регистра букв исходной строки `[$выражение]`. Пример:"
  759. "```qsp"
  760. "UCASE('TexT#') & ! -> 'TEXT#'"
  761. "```"
  762. ] |> String.concat "\n"
  763. Ucase, dscr, arg String String
  764. let dscr =
  765. [
  766. "`VAL([$выражение])` - переводит строку цифр `[$выражение]` в соответствующее число. Если [$выражение] равно '' (пустая строка) или если оно содержит не-цифры, то возвращается 0."
  767. ] |> String.concat "\n"
  768. Val, dscr, arg String Numeric
  769. let dscr =
  770. [
  771. "возвращает название выделенного действия."
  772. ] |> String.concat "\n"
  773. Selact, dscr, unit' String
  774. ]
  775. let functionBySymbolic =
  776. functions
  777. |> List.map (fun (name, dscr, sign) ->
  778. name, {| SymbolicName = name; Description = dscr; Signature = sign |})
  779. |> Map.ofList
  780. let functionsByName =
  781. functions
  782. |> List.map (fun (name, dscr, sign) ->
  783. let stringName = (string name).ToLower()
  784. stringName, {| SymbolicName = name; Description = dscr; Signature = sign |})
  785. |> Map.ofList
  786. /// Да-да, всё это — процедуры: они что-то выполняют и никуда не перемещают.
  787. let procedures =
  788. [
  789. let dscr =
  790. [
  791. "`OPENGAME [$выражение]` - если `[$выражение]` равно '' (пустая строка) или отсутствует, то вызов окна загрузки состояния игры, иначе загрузка состояния из указанного файла. См. также локацию-обработчик события загрузки игры."
  792. ] |> String.concat "\n"
  793. let os =
  794. [
  795. [||], ()
  796. [| String |], ()
  797. ] |> JustOverloads
  798. "opengame", dscr, os
  799. let dscr =
  800. [
  801. "`CMDCLEAR` или `CMDCLR` - очистка строки ввода."
  802. ] |> String.concat "\n"
  803. "cmdclear", dscr, unit'
  804. let dscr =
  805. [
  806. "`CMDCLEAR` или `CMDCLR` - очистка строки ввода."
  807. ] |> String.concat "\n"
  808. "cmdclr", dscr, unit'
  809. let dscr =
  810. [
  811. "`SAVEGAME [$выражение]` - если `[$выражение]` равно '' (пустая строка) или отсутствует, то вызов окна сохранения состояния игры, иначе сохранение состояния в указанный файл. См. также локацию-обработчик события сохранения игры."
  812. ] |> String.concat "\n"
  813. let os =
  814. [
  815. [||], ()
  816. [| String |], ()
  817. ] |> JustOverloads
  818. "savegame", dscr, os
  819. let dscr =
  820. [
  821. "`OPENQST [$выражение]` - открытие и запуск заданного файла игры. При использовании данного оператора, не происходит удаления переменных, удаления предметов инвентаря, очистки дополнительного описания и строки ввода, а также остановки проигрываемых файлов (для этого в начале загружаемой игры можно выполнить \"KILLALL & CLS & CLOSE ALL\")."
  822. ] |> String.concat "\n"
  823. "openqst", dscr, arg String
  824. let dscr =
  825. [
  826. "`ADDQST [$выражение]` - из заданного файла игры добавляет все локации, названия которых отсутствуют среди текущих игровых локаций. Загруженные локации полностью эквивалентны локациям из основного файла игры."
  827. ] |> String.concat "\n"
  828. "addqst", dscr, arg String
  829. let dscr =
  830. "Синоним `addqst`"
  831. "addlib", dscr, arg String
  832. let dscr =
  833. "Синоним `addqst`"
  834. "inclib", dscr, arg String
  835. let dscr =
  836. [
  837. "KILLQST - удаляет все локации, добавленные с помощью оператора `ADDQST`"
  838. ] |> String.concat "\n"
  839. "killqst", dscr, unit'
  840. "freelib", dscr, unit'
  841. "dellib", dscr, unit'
  842. let dscr =
  843. [
  844. "`DELACT [$название]` или `DEL ACT [$название]` - удаляет действие из списка действий на локации (если такое действие существует). Например:"
  845. "```qsp"
  846. "DELACT 'Идти вперед'"
  847. "DELACT $SELACT"
  848. "```"
  849. ] |> String.concat "\n"
  850. "delact", dscr, arg String
  851. let dscr =
  852. [
  853. "CLA - очистка списка текущих действий."
  854. ] |> String.concat "\n"
  855. "cla", dscr, unit'
  856. let dscr =
  857. [
  858. "`ADDOBJ [$название],[$путь к файлу изображения],[#индекс]` или `ADD OBJ [$название],[$путь к файлу изображения],[#индекс]` - добавление предмета с названием [$название] и изображением [$путь к файлу изображения] в инвентарь на место с номером [#индекс]."
  859. ""
  860. "Параметр [#индекс] может отсутствовать. По умолчанию предметы добавляются в конец списка."
  861. ""
  862. "Индексация предметов рюкзака ведётся с 1."
  863. ""
  864. "Параметр [$путь к файлу изображения] может отсутствовать, значение по умолчанию - `''`."
  865. ""
  866. "Обратите внимание - для использования одинаковых предметов инвентаря, например денег, патронов и т.п., лучше использовать дополнительную переменную, обозначающую количество этих предметов, чтобы не загромождать инвентарь списком из 137 предметов Рубль / Патрон. Для хранения числа предметов можно использовать массивы, индексируемые через строки:"
  867. ""
  868. "```qsp"
  869. "OBJECTS['деньги'] = 12"
  870. "OBJECTS['патроны'] = 137"
  871. "'Количество: <<OBJECTS[$getobj(countobj)]>>'"
  872. "```"
  873. ] |> String.concat "\n"
  874. let os =
  875. [
  876. [| String |], ()
  877. [| String; String |], ()
  878. [| String; String; Numeric |], ()
  879. ] |> JustOverloads
  880. "addobj", dscr, os
  881. let dscr =
  882. [
  883. "`DELOBJ [$название]` или `DEL OBJ [$название]` - удаление предмета из рюкзака, если таковой имеется. Также см. локацию-обработчик удаления предмета."
  884. ] |> String.concat "\n"
  885. "delobj", dscr, arg String
  886. let dscr =
  887. [
  888. "`KILLOBJ [#выражение]` - удаление предмета, расположенного в заданной позиции. Если параметр [#выражение] не указан, то очистка рюкзака."
  889. "Индексация предметов рюкзака ведётся с 1. Также см. локацию-обработчик удаления предмета."
  890. ] |> String.concat "\n"
  891. let os =
  892. [
  893. [||], ()
  894. [| Numeric |], ()
  895. ] |> JustOverloads
  896. "killobj", dscr, os
  897. let dscr =
  898. [
  899. "`UNSELECT` или `UNSEL` - отмена выбора предмета. При выборе играющим какого-либо предмета, он остаётся выделенным. Данная команда снимает выделение."
  900. ] |> String.concat "\n"
  901. "unsel", dscr, unit'
  902. "unselect", dscr, unit'
  903. let dscr =
  904. [
  905. "KILLALL - эквивалентен конструкции `KILLVAR & KILLOBJ`."
  906. ] |> String.concat "\n"
  907. "killall", dscr, unit'
  908. let dscr =
  909. [
  910. "`KILLVAR [$название массива],[#индекс элемента]` - удаление элемента массива. Если индекс элемента не указан, то очищается весь массив. Если оператор вызван без аргументов, то удаляются все переменные - обычно применяется в начале игры, чтобы при возврате в начальную локацию после неудачного прохождения какого-то этапа игры обнулить все переменные (в противном случае, может оказаться, что запертые двери уже открыты, жена похищена до свадьбы, а Баба-Яга уже отдала кому-то нужный клубочек). Примеры:"
  911. "```qsp"
  912. "KILLVAR"
  913. "KILLVAR 'a'"
  914. "KILLVAR 'a',3"
  915. "```"
  916. ] |> String.concat "\n"
  917. let funcs =
  918. [
  919. [| String; Numeric |], ()
  920. [| String; |], ()
  921. [||], ()
  922. ] |> JustOverloads
  923. "killvar", dscr, funcs
  924. let dscr =
  925. [
  926. "`COPYARR [$массив-приёмник],[$массив-источник],[#начало],[#количество]` - копирование в массив-приёмник [#количество] элементов из массива-источника начиная с элемента под номером [#начало]. Размер массива-приёмника при копировании не имеет значения. "
  927. " - Параметр [#количество] является необязательным. По умолчанию - до конца массива-источника."
  928. " - Параметр [#начало] является необязательным. По умолчанию - 0."
  929. " - Не имеет значения, указываете ли вы $ перед названием массива или нет. Копируются элементы и со строковыми, и с числовыми значениями. "
  930. "Примеры:"
  931. "```qsp"
  932. "COPYARR '$a','$b'"
  933. "COPYARR 'a','b'"
  934. "COPYARR $arrname1,$arrname2,10,5"
  935. "COPYARR 'a<<$arrname1>>','a<<$arrname2>>'"
  936. "```"
  937. ] |> String.concat "\n"
  938. let funcs =
  939. [
  940. [| String; String |], ()
  941. [| String; String; Numeric |], ()
  942. [| String; String; Numeric; Numeric |], ()
  943. ] |> JustOverloads
  944. "copyarr", dscr, funcs
  945. let dscr =
  946. [
  947. "`CLEAR` или `CLR` - очистка окна пользователя."
  948. ] |> String.concat "\n"
  949. "clear", dscr, unit'
  950. let dscr =
  951. [
  952. "`CLEAR` или `CLR` - очистка окна пользователя."
  953. ] |> String.concat "\n"
  954. "clr", dscr, unit'
  955. let dscr =
  956. [
  957. "`CLOSE [$путь к звуковому файлу]` - остановка проигрывания звукового файла с заданным названием."
  958. "`CLOSE ALL` - остановка проигрывания всех активных звуковых файлов."
  959. ] |> String.concat "\n"
  960. "close", dscr, arg String
  961. let dscr = "`CLOSE ALL` - остановка проигрывания всех активных звуковых файлов."
  962. "close all", dscr, unit' // особый-преособый случай
  963. let dscr =
  964. [
  965. "`CLS` - эквивалентен конструкции `CLEAR & *CLEAR & CLA & CMDCLEAR`, т.е. очищает всё, кроме списка предметов."
  966. ] |> String.concat "\n"
  967. "cls", dscr, unit'
  968. let dscr =
  969. [
  970. "`DYNAMIC [$строка кода],[параметр 1],[параметр 2], ...` - выполнение кода. Данный оператор позволяет динамически генерировать код игры. Переданные параметры хранятся в массиве `ARGS`. После выполнения кода предыдущие значения `ARGS` восстанавливаются. Примеры:"
  971. "```qsp"
  972. "DYNAMIC '$a=\"string<<$b>>\"'"
  973. "DYNAMIC '$a'"
  974. "DYNAMIC 'if $a=\"string\":''text!'''"
  975. "DYNAMIC \""
  976. "$args[0]"
  977. "addobj $args[1]"
  978. "\",'Текст','Вилка'"
  979. "```"
  980. ] |> String.concat "\n"
  981. "dynamic", dscr, argAndArgList String Any
  982. let dscr =
  983. [
  984. "`MENU [$выражение]` - вызов меню с заданным названием"
  985. ] |> String.concat "\n"
  986. "menu", dscr, arg String
  987. let dscr =
  988. [
  989. "`MSG [выражение]` - вывод заданного сообщения в информационном окне."
  990. ] |> String.concat "\n"
  991. "msg", dscr, arg String
  992. let dscr =
  993. [
  994. "`NL [выражение]` - переход на новую строку (перевод каретки), затем вывод текста в окне пользователя. Если `[выражение]` не указано, то перевод строки. Отличается от `PL` порядком вывода текста."
  995. ] |> String.concat "\n"
  996. let funcs =
  997. [
  998. [| String |], ()
  999. [| |], ()
  1000. ] |> JustOverloads
  1001. "nl", dscr, funcs
  1002. let dscr =
  1003. [
  1004. "`P [выражение]` - вывод текста в окно пользователя (по умолчанию находится справа внизу, обычно служит для вспомогательных целей)."
  1005. ] |> String.concat "\n"
  1006. "p", dscr, arg String
  1007. let dscr =
  1008. [
  1009. "`PL [выражение]` - вывод текста, затем переход на новую строку в окне пользователя. Если `[выражение]` не указано, то перевод строки"
  1010. ] |> String.concat "\n"
  1011. let funcs =
  1012. [
  1013. [| |], ()
  1014. [| String |], ()
  1015. ] |> JustOverloads
  1016. "pl", dscr, funcs
  1017. let dscr =
  1018. [
  1019. "`PLAY [$путь к звуковому файлу],[#громкость]` - проигрывание звукового файла с заданным названием и громкостью. Громкость указывается в процентах от 0 до 100."
  1020. "Параметр `[#громкость]` может отсутствовать, при этом громкость принимается равной 100%. Примеры:"
  1021. "`PLAY 'sound/music.mp3'` - проигрывает файл с громкостью 100%"
  1022. "`PLAY 'sound/music.mp3',50` - проигрывает файл в половину возможной громкости"
  1023. "`PLAY 'sound/music.mp3',0` - проигрывает файл с громкостью 0% (без звука)"
  1024. "`PLAY '<<$file>>.mid',volume` - проигрывает файл, имя которого хранится в $file (расширение \"mid\") с громкостью, значение которой задано в volume"
  1025. "`PLAY $file,volume` - аналогично"
  1026. "Если файл уже проигрывается, то изменяется громкость звучания без его \"перезапуска\". Поддерживается множество различных аудиоформатов и одновременное звучание до 32-х композиций."
  1027. ] |> String.concat "\n"
  1028. "play", dscr, argsAndOptional [ String ] Numeric
  1029. let dscr =
  1030. [
  1031. "обновление интерфейса (а также смена цветов, шрифта, назначенных с помощью системных переменных `BCOLOR`, `FCOLOR`, `LCOLOR`, `FSIZE`, `$FNAME`)."
  1032. ] |> String.concat "\n"
  1033. "refint", dscr, unit'
  1034. let dscr =
  1035. [
  1036. "`SETTIMER [#выражение]` - задает интервал таймера для локации-счётчика (по умолчанию 500мс, т.е. локация-счётчик обрабатывается 2 раза в секунду). Также влияет на частоту автоматического обновления интерфейса."
  1037. ] |> String.concat "\n"
  1038. "settimer", dscr, arg Numeric
  1039. let dscr =
  1040. [
  1041. "`SHOWACTS [#выражение]` - если значение выражения отлично от 0, то показывает список действий, иначе скрывает его. Примеры:"
  1042. "`SHOWACTS 1` - показывает список действий"
  1043. "`SHOWACTS 0` - скрывает список действий"
  1044. ] |> String.concat "\n"
  1045. "showacts", dscr, arg Numeric
  1046. let dscr =
  1047. [
  1048. "`SHOWINPUT [#выражение]` - если значение выражения отлично от 0, то показывает строку ввода, иначе скрывает её."
  1049. ] |> String.concat "\n"
  1050. "showinput", dscr, arg Numeric
  1051. let dscr =
  1052. [
  1053. "`SHOWOBJS [#выражение]` - если значение выражения отлично от 0, то показывает список предметов, иначе скрывает его."
  1054. ] |> String.concat "\n"
  1055. "showobjs", dscr, arg Numeric
  1056. let dscr =
  1057. [
  1058. "`SHOWSTAT [#выражение]` - если значение выражения отлично от 0, то показывает дополнительное описание, иначе скрывает его."
  1059. ] |> String.concat "\n"
  1060. "showstat", dscr, arg Numeric
  1061. let dscr =
  1062. [
  1063. "`VIEW [$путь к графическому файлу]` - просмотр картинки из указанного файла. Если вместо `[$путь к графическому файлу]` указана пустая строка (`''`) или параметр не указан, то это скроет окно с картинкой."
  1064. ] |> String.concat "\n"
  1065. let funcs =
  1066. [
  1067. [| String |], ()
  1068. [| |], ()
  1069. ] |> JustOverloads
  1070. "view", dscr, funcs
  1071. let dscr =
  1072. [
  1073. "`WAIT [#выражение]` - остановка выполнения программы на заданное количество миллисекунд (1 секунда = 1000 миллисекунд)."
  1074. ] |> String.concat "\n"
  1075. "wait", dscr, arg Numeric
  1076. ]
  1077. let jump =
  1078. let dscr =
  1079. [
  1080. "`JUMP [$выражение]` - переход в текущем коде (при обработке локации / выбора действия) на метку `[$выражение]`. Метка на локации обозначается как `:[название метки]`. После описания метки (через \"&\") могут идти операторы. Если интерпретатор находит случайную метку, то он её просто игнорирует. Например:"
  1081. "```qsp"
  1082. "jump 'КонеЦ'"
  1083. "p 'Это сообщение не будет выведено'"
  1084. ":конец"
  1085. "p 'А это сообщение пользователь увидит'"
  1086. "```"
  1087. "С помощью оператора `JUMP` можно организовывать циклы:"
  1088. "```qsp"
  1089. "s = 0"
  1090. ":loop"
  1091. "if s < 9:"
  1092. " s=s+1"
  1093. " pl s"
  1094. " jump 'LOOP'"
  1095. "end"
  1096. "p 'Всё!'"
  1097. "```"
  1098. "Оператор `JUMP` также полезен во время отладки квеста, чтобы \"обойти\" группу операторов, которые временно не нужны."
  1099. ] |> String.concat "\n"
  1100. "jump", dscr, arg String
  1101. let transferOperators =
  1102. [
  1103. let dscr =
  1104. [
  1105. "`GOSUB [$выражение],[параметр 1],[параметр 2], ...` или `GS [$выражение],[параметр 1],[параметр 2], ...` - обработка локации с названием `[$выражение]`. Базовое описание локации добавляется к текущему описанию, базовые действия добавляются к текущим действиям, и происходит выполнение операторов в поле \"Выполнить при посещении\", затем возврат на исходную строку (продолжение выполнения программы)."
  1106. "Переданные параметры хранятся в массиве `ARGS`. После обработки локации предыдущие значения `ARGS` восстанавливаются. Примеры:"
  1107. "```qsp"
  1108. "GS 'ход' & ! обработка локации \"ход\". Массив `ARGS` пуст."
  1109. "GS $loc,1 & ! обработка локации, название которой хранится в $loc с передачей одного параметра. ARGS[0] равен 1."
  1110. "GS 'ход',$var,2,'данные' & ! обработка локации \"ход\" с передачей 3-х параметров. `$ARGS[0]` равен значению `$var`, `ARGS[1]` равен 2, `$ARGS[2]` содержит строку \"данные\"."
  1111. "```"
  1112. ] |> String.concat "\n"
  1113. let sign = argAndArgList String Any
  1114. "gosub", dscr, sign
  1115. "gs", dscr, sign
  1116. let dscr =
  1117. [
  1118. "`GOTO [$выражение],[параметр 1],[параметр 2], ...` или `GT [$выражение],[параметр 1],[параметр 2], ...` - переход на локацию с названием `[$выражение]`. Поле основного описания локации, а также список текущих действий заменяются описанием и действиями новой локации."
  1119. "Переданные параметры хранятся в массиве `ARGS`. Примеры:"
  1120. "```qsp"
  1121. "GT 'локация' & ! переход на локацию \"локация\". Массив `ARGS` пуст."
  1122. "GT 'локация',1,'данные' & ! переход на локацию \"локация\" с передачей 2-х параметров. `ARGS[0]` равен 1, `$ARGS[1]` содержит строку \"данные\"."
  1123. "```"
  1124. ] |> String.concat "\n"
  1125. let sign = argAndArgList String Any
  1126. "goto", dscr, sign
  1127. "gt", dscr, sign
  1128. let dscr =
  1129. [
  1130. "`XGOTO [$выражение],[параметр 1],[параметр 2], ...` или `XGT [$выражение],[параметр 1],[параметр 2], ...` - отличается от \"`GOTO` / `GT`\" тем, что при переходе не очищается поле основного описания локации, а базовое описание новой локации добавляется к текущему основному описанию. Тем не менее, список действий заменяется действиями новой локации."
  1131. ] |> String.concat "\n"
  1132. let sign = argAndArgList String Any
  1133. "xgoto", dscr, sign
  1134. "xgt", dscr, sign
  1135. ]
  1136. let transferOperatorsSet =
  1137. transferOperators
  1138. |> List.map (fun (name, dscr, sign) -> name)
  1139. |> Set.ofList
  1140. /// Всевозможные процедуры
  1141. let procs =
  1142. jump::(procedures @ transferOperators)
  1143. |> List.map (fun (name, dscr, sign) -> name, ((dscr:Description), sign))
  1144. |> Map.ofList
  1145. let exprSymbolicOperators =
  1146. let arg x (return':VarType) = arg x, return'
  1147. let unit' (return':VarType) = unit', return'
  1148. let args xs (return':VarType) = args xs, return'
  1149. let argList typ (return':VarType) = argList typ, return'
  1150. let argAndArgList x typ (return':VarType) = argAndArgList x typ, return'
  1151. [
  1152. let dscr =
  1153. "`[$выражение 1] & [$выражение 2]` - операция объединения строковых выражений."
  1154. "&", dscr, args [String; String] String
  1155. ]
  1156. let exprNamedOperators =
  1157. let arg x (return':VarType) = arg x, return'
  1158. let unit' (return':VarType) = unit', return'
  1159. let args xs (return':VarType) = args xs, return'
  1160. let argList typ (return':VarType) = argList typ, return'
  1161. let argAndArgList x typ (return':VarType) = argAndArgList x typ, return'
  1162. [
  1163. // Для значения "верно" настоятельно рекомендуется использовать -1.
  1164. let dscr =
  1165. [
  1166. "`[#выражение 1] AND [#выражение 2]` - операция \"и\". Если оба рядом стоящие выражения верны, то верно и всё выражение."
  1167. ] |> String.concat "\n"
  1168. "and", dscr, args [Numeric; Numeric] Numeric
  1169. let dscr =
  1170. [
  1171. "`[#выражение 1] OR [#выражение 2]` - операция \"или\". Если хотя бы одно из рядом стоящих выражений верно, то верно и всё выражение."
  1172. ] |> String.concat "\n"
  1173. "or", dscr, args [Numeric; Numeric] Numeric
  1174. let dscr =
  1175. [
  1176. "`[#выражение 1] MOD [#выражение 2]` - операция вычисления остатка от деления."
  1177. ] |> String.concat "\n"
  1178. "mod", dscr, args [Numeric; Numeric] Numeric
  1179. let dscr =
  1180. [
  1181. "`NO [#выражение]` - отрицание. Верно, если `[#выражение]` ложно и наоборот (аналогично \"NOT\" в Basic)."
  1182. ] |> String.concat "\n"
  1183. "no", dscr, arg Numeric Numeric
  1184. let dscr =
  1185. [
  1186. "`OBJ [$выражение]` - верно, если в рюкзаке есть предмет `[$выражение]`."
  1187. ] |> String.concat "\n"
  1188. "obj", dscr, arg String Numeric
  1189. let dscr =
  1190. [
  1191. "`LOC [$выр]` - верно, если в игре есть локация с названием `[$выр]`."
  1192. ] |> String.concat "\n"
  1193. "loc", dscr, arg String Numeric
  1194. ]
  1195. let keywords =
  1196. [
  1197. let dscr =
  1198. [
  1199. "`IF [#выражение]:[оператор1] & [оператор2] & ... ELSE [оператор3] & [оператор4] & ...` - если `[#выражение]` верно (не равно 0), то выполнить заданные операторы до ключевого слова `ELSE`, иначе выполнить операторы после `ELSE`."
  1200. "Если ключевое слово `ELSE` не указано, то при верном значении [#выражение], выполняются все операторы, находящиеся после символа `:`."
  1201. "Примеры:"
  1202. "```qsp"
  1203. "if ((a+b)/c)=45+54 or (b<5 or c>45) and no obj 'лопата' and $f=$vvv+'RRRRR':p 'OK' & goto 'Next'"
  1204. "if был_здесь[$curloc]:exit"
  1205. "if a<3:jump 'sss'"
  1206. "if $имя = '':msg 'Введите имя!' & jump 'ввод'"
  1207. "if a+b=2:c=30 & gt 'next' else c=10"
  1208. "```"
  1209. ] |> String.concat "\n"
  1210. "if", dscr
  1211. "else", dscr
  1212. "elseif", dscr
  1213. "end", "Завершает конструкции `ACT`, `IF` или `FOR`."
  1214. let dscr =
  1215. [
  1216. "`ACT [$название],[$путь к файлу изображения]:[оператор] & [оператор] & ...` - добавление действия к существующим на локации."
  1217. "К действиям добавляется новое с описанием `[$название]` и изображением `[$путь к файлу изображения]`. При нажатии на него выполнятся заданные операторы."
  1218. "Параметр `[$путь к файлу изображения]` может отсутствовать, при этом действие добавится без изображения."
  1219. ] |> String.concat "\n"
  1220. "act", dscr
  1221. let dscr =
  1222. [
  1223. "`SET [название переменной]=[выражение]`, `LET [название переменной]=[выражение]` или `[название переменной]=[выражение]` - установка значения переменной. Если нужно установить текстовое значение переменной, то перед её названием ставится `$`."
  1224. "Примеры:"
  1225. "```qsp"
  1226. "SET A=123"
  1227. "SET $B='строка'"
  1228. "LET C=A"
  1229. "D=456"
  1230. "$D='ещё строка'"
  1231. "$D='и ещё"
  1232. " одна"
  1233. "строка'"
  1234. "```"
  1235. ] |> String.concat "\n"
  1236. "set", dscr
  1237. "let", dscr
  1238. let dscr =
  1239. [
  1240. "завершение выполнения текущего кода (преждевременный выход из подпрограммы / обработчика какого-либо события...)."
  1241. ] |> String.concat "\n"
  1242. "exit", dscr
  1243. ]