skills.tin 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584
  1. #nop vim: set filetype=tt:;
  2. /*
  3. 本文件属于 PaoTin++ 的一部分
  4. ===========
  5. PaoTin++ © 2020~2023 的所有版权均由担子炮(dzp <danzipao@gmail.com>) 享有并保留一切法律权利
  6. 你可以在遵照 GPLv3 协议的基础之上使用、修改及重新分发本程序。
  7. ===========
  8. */
  9. #var basic_char_skills[META] {
  10. {NAME} {技能列表}
  11. {DESC} {解析 skills 命令的输出结果,并写入到 char[Skills]}
  12. {AUTHOR} {担子炮}
  13. {NOTE} {技能小点和激发关系分别由 skbrief 和 jifa 命令提供,都合并在一起}
  14. {CONFIG} {
  15. }
  16. };
  17. /*
  18. 2024-12-02 09:37:00 INPUT: sk
  19. ╭───技能列表(共二十项)──────────┬──────┬───────╮
  20. │技能 │描述 │级别/上限 │
  21. ├───二项职业技能──────────────┼──────┼───────┤
  22. │ 火眼金睛(anti-disguise) │不堪一击 │ 1.00/346 │
  23. │ 占卜之术(divination) │不足挂齿 │ 83.32/346 │
  24. ├───五项基本知识──────────────┼──────┼───────┤
  25. │ 鉴定之术(identification) │初窥门径 │ 50.00/- │
  26. │ 读书写字(literate) │已有小成 │ 257.16/- │
  27. │+音律(music) │略知一二 │ 102.00/- │
  28. │ 奇门八卦(qimen-bagua) │已有小成 │ 250.00/- │
  29. ├───八项基本功夫──────────────┼──────┼───────┤
  30. │ 基本轻功(dodge) │平淡无奇 │ 325.01/346 │
  31. │ 基本指法(finger) │粗通皮毛 │ 346.00/346 │
  32. │ 基本内功(force) │平淡无奇 │ 315.04/346 │
  33. │ 基本手法(hand) │粗通皮毛 │ 346.00/346 │
  34. │ 基本招架(parry) │粗通皮毛 │ 346.00/346 │
  35. │ 基本掌法(strike) │粗通皮毛 │ 346.00/346 │
  36. │ 基本剑法(sword) │平淡无奇 │ 327.00/346 │
  37. ├───十项特殊功夫──────────────┼──────┼───────┤
  38. │□碧海神功(bihai-shengong) │平淡无奇 │ 314.07/346 │
  39. │□兰花拂穴手(fuxue-shou) │粗通皮毛 │ 346.00/346 │
  40. │□落英身法(luoying-shenfa) │平淡无奇 │ 325.00/346 │
  41. │□落英神剑掌(luoying-zhang) │粗通皮毛 │ 346.00/346 │
  42. │□弹指神通(tanzhi-shentong) │粗通皮毛 │ 346.00/346 │
  43. │□玉箫剑法(yuxiao-jian) │平淡无奇 │ 327.00/346 │
  44. ├───────────────────────┴──────┴───────┤
  45. │共使用了27.5个技能槽位,无技能槽位限制。级别上限:+1.67%。 │
  46. ╰─────────────────────────────北大侠客行────╯
  47. */
  48. load-lib event;
  49. event.Define {char/skills} {无参} {$MODULE} {已经获取到 skills 命令输出结果,并更新 char[Skills]。};
  50. event.Define {char/skbrief} {无参} {$MODULE} {已经获取到 skbrief 命令输出结果,并更新 char[Skills]。};
  51. #func {basic_char_skills.Init} {
  52. #class data/basic/char open;
  53. #var char[Skills] {};
  54. #var char-skill-limit {1};
  55. #class data/basic/char close;
  56. #delay char.skills.init {skills;jifa} 1;
  57. #return true;
  58. };
  59. #alias {skills} {char.Skills};
  60. #alias {sk} {char.Skills};
  61. #alias {cha} {char.Skills};
  62. #alias {skbrief} {char.Skbrief {%1} nogag};
  63. VAR {技能 ID 到技能名称的转换} char.skills.id2name {};
  64. #alias {char.Skills} {
  65. #local args {%0};
  66. #if { "$args" == "" } {
  67. #line oneshot #action {^╭───技能列表(共%*项){(─|┬)*}──╮$} {
  68. #var char[Skills][count] {@math.ParseCN{%%1}};
  69. #local rawLine {%%99};
  70. #replace rawLine {)%C─} {)&1────};
  71. #echo {%s} {@Beautify{{$rawLine}}};
  72. #line gag;
  73. char.skills.parse.output;
  74. };
  75. };
  76. xtt.Send {skills %0};
  77. };
  78. #alias {char.skills.parse.output} {
  79. #class {ParseSkills} open;
  80. #var char[Skills][currentType] {};
  81. #var char[Skills][nameList] {};
  82. #gag {^│技能 %s │描述 %s │级别/上限 %s │};
  83. #action {^├───%%1项%%2──} {
  84. #var char[Skills][currentType] {%%2};
  85. #local rawLine {%%99};
  86. #replace rawLine {%C├───%C%*项%*%C──} {&1├───&2&3项&4&5─────};
  87. #echo {%s} {@Beautify{{$rawLine}}};
  88. #line gag;
  89. };
  90. #sub {~^%C│%*(%*)%*│%*│%*/%C-%*│} {%%1│%%2(%%3)%%4 │%%5│%%6/%%7-%%8│};
  91. #nop □已激发,△另一种激发,☆真传武功,+有子技能。;
  92. #action {^│{□|△|☆|+| }%S(%S) {|(?:+)+}%!s │%S {|↑}%!s │%!s %S/%S %!s│{|ID=char.skills}} {
  93. #local rawLine {%%99};
  94. #local type {$char[Skills][currentType]};
  95. #local enabled {%%1};
  96. #local name {%%2};
  97. #local code {%%3};
  98. #local prof {%%4};
  99. #local rank {%%5};
  100. #local level {%%7};
  101. #local limit {%%8};
  102. #tab {$code};
  103. #if { "$limit" == "-" } {
  104. #local limit {0};
  105. };
  106. #replace name { } {};
  107. #if { "$enabled" == "{□|△}" } {
  108. #format enabled {true};
  109. };
  110. #else {
  111. #format enabled {false};
  112. };
  113. #if { "$prof" == "+" } {
  114. #local prof {{color}{@str.WordColor{{$rawLine};{$prof}}}{mark}{$prof}};
  115. };
  116. #list char[Skills][nameList] add {$name};
  117. #var {char[Skills][$name]} {
  118. $char[Skills][$name]
  119. {name} {$name}
  120. {type} {$type}
  121. {enabled} {$enabled}
  122. {code} {$code}
  123. {prof} {$prof}
  124. {rank} {$rank}
  125. {level} {$level}
  126. {limit} {$limit}
  127. };
  128. #var char.skills.id2name[$code] {$name};
  129. #if { $char-skill-limit < $limit } {
  130. #var char-skill-limit $limit;
  131. };
  132. #if { $limit == 0 } {
  133. #return;
  134. };
  135. #nop 接下来给技能加上彩色进度条,用来表示当前级别距离上限的程度;
  136. #replace rawLine {^%*│%*(%S)%C{(?:+)*}%C│%*│%+1c%c %*│%*$} {&1│&2@char.Skills.colorIt{{&3};{&4&5};{&6};{&9};$level;$limit;10}│&7│&8&9 &10│&11};
  137. #echo {%s} {@Beautify{{$rawLine}}};
  138. #line gag;
  139. };
  140. #sub {├─%*──┴─%*──┴──%*──┤} {├─%%1────────┴─%%2──┴──%%3──┤};
  141. #action {^│共使用了%*个技能槽位,空余槽位(%*)。级别上限:%*。%s│} {
  142. #local rawLine {%%99};
  143. #replace rawLine { %C│} { &1│};
  144. #echo {%s} {@Beautify{{$rawLine}}};
  145. #line gag;
  146. };
  147. #action {^│本日高级演练,使用点数:%*,潜能:%*。%s│} {
  148. #local rawLine {%%99};
  149. #replace rawLine { %C│} { &1│};
  150. #echo {%s} {@Beautify{{$rawLine}}};
  151. #line gag;
  152. };
  153. #action {^╰───{(┴|─)*}─%S────╯{|ID=char.skills}$} {
  154. #local rawLine {%%99};
  155. #replace rawLine {╯} {───╯};
  156. #echo {%s} {@Beautify{{$rawLine}}};
  157. #line gag;
  158. char.skills.parse.done;
  159. };
  160. #action {^你不是查看过吗?{|ID=char/skills}$} {
  161. char.skills.parse.done;
  162. };
  163. #alias {char.skills.parse.done} {
  164. #local __unused {%%0};
  165. #local nameList {$char[Skills][nameList]};
  166. #local count {$char[Skills][count]};
  167. #unvar char[Skills][currentType];
  168. #unvar char[Skills][nameList];
  169. #unvar char[Skills][count];
  170. #class {ParseSkills} kill;
  171. #if { &nameList[] != $count } {
  172. #line sub var #delay 0 {
  173. errLog skills 命令结果解析不完整,识别到了 &nameList[] 条记录。数据可能有误,请联系开发者。;
  174. };
  175. #return;
  176. };
  177. #list nameList collapse {|};
  178. #local skillName {};
  179. #foreach {*char[Skills][]} {skillName} {
  180. #if { "$skillName" != "{$nameList}" } {
  181. #unvar {char[Skills][$skillName]};
  182. };
  183. };
  184. event.Emit {char/skills};
  185. };
  186. event.ClassHandleOnce GA {char.skills} {char} {char.skills.parse.done};
  187. #class {ParseSkills} close;
  188. };
  189. #func {char.Skills.colorIt} {
  190. #local code {%1};
  191. #local prof {%2};
  192. #local space {@str.Plain{%3}};
  193. #local pColor {%4};
  194. #local level {%5};
  195. #local limit {%6};
  196. #local barLen {%7};
  197. #local text {($code)$prof $space };
  198. #local textLen {@str.Len{$text}};
  199. #local leftLen {@math.Eval{$textLen - $barLen - 5}};
  200. #local left {@str.Left{{$text}; $leftLen}};
  201. #local right {@str.Right{{$text}; $barLen}};
  202. #local percent {@math.Int{@math.Eval{$level * 100 / $limit}}};
  203. #local color {@util.Grade{$percent;<271>;15;<171>;30;<203>;60;<274>;90;<134>;100;<132>;101;<506>}};
  204. #local rest {@math.Eval{100 - $percent}};
  205. #local pStr {@str.Format{%%3d%;$percent}};
  206. #return {$left$pColor$pStr<299> @util.ColorBar{{$right};$color;$percent;<g08>;$rest}};
  207. };
  208. #alias {char.Skbrief} {
  209. #local skillID {%1};
  210. #if { "$skillID" == "" } {
  211. errLog 用法: skbrief <技能ID>;
  212. #return;
  213. };
  214. #alias {char.Skbrief.update} {
  215. #local lvl {%%1};
  216. #local point {%%2};
  217. #local skillID {%1};
  218. #local skillName {$char.skills.id2name[$skillID]};
  219. #if { "$skillName" == "" } {
  220. errLog skills 相关触发出现 BUG,请联系开发者。;
  221. #return;
  222. };
  223. #local delta {@math.Eval{$point - $char[Skills][$skillName][point]}};
  224. #if { $char[Skills][$skillName][lvl] != $lvl } {
  225. #local delta 0;
  226. };
  227. #var char[Skills][$skillName][lvl] {$lvl};
  228. #var char[Skills][$skillName][point] {$point};
  229. #local level {};
  230. #nop 领悟有时候会领悟过头,小点偶尔会超过等级的平方。;
  231. #nop XXX: 这个时候就强制限制到 xxx.99,以免引起重大误解。;
  232. #if { $point >= $lvl ** 2 } {
  233. #local level {@math.Eval{$lvl + 0.99}};
  234. };
  235. #else {
  236. #math level {$lvl*1.0000000000000000 + $point*1.00 / ($lvl ** 2)};
  237. #replace level {^%*.%.%.%*$} {&1.&2&3};
  238. };
  239. #var char[Skills][$skillName][level] {$level};
  240. #local limit {@char.SkillLimit{$skillName}};
  241. #local jifa {@char.GetJifaSkill{$skillName}};
  242. #local jifaLvl {@char.SkillLevel{$jifa}};
  243. #local delta {@str.FormatIfElse{$delta > 0; {(<129>+<299>%s)}; {}; $delta}};
  244. #local desc {<== <039>$level<299> / <069>$limit<299> <== <Ffc0>$skillName<299>};
  245. #if { "$jifa" != "" } {
  246. #cat desc { 当前激发至 <059>$jifa<299>($jifaLvl)};
  247. };
  248. #else {
  249. #cat desc { <019>该技能尚未激发<299>};
  250. };
  251. #line sub var #line oneshot #sub {^#{$lvl}/{$point}$} {#<129>$lvl<299>/<029>$point<299>$delta $desc};
  252. event.Emit {char/skbrief};
  253. };
  254. #line oneshot #alias {char.Skbrief.parse} {
  255. #line oneshot #action {^系统回馈:R:skbrief-begin-%%1$} {
  256. #class char-skbrief-parse-output-%%1 open;
  257. #line oneshot #action {^#%d/%d{|ID=char/skbrief-%%1}$} {
  258. #local lvl {%%%%1};
  259. #local point {%%%%2};
  260. char.Skbrief.update {$lvl} {$point};
  261. #local gag {@default{%2;gag}};
  262. #if { "$gag" == "gag" } {
  263. #line gag;
  264. };
  265. };
  266. #line oneshot #action {^系统回馈:R:skbrief-end-%%1$} {
  267. #line gag;
  268. #class char-skbrief-parse-output-%%1 kill;
  269. };
  270. #class char-skbrief-parse-output-%%1 close;
  271. #line gag;
  272. };
  273. };
  274. #local uuid {@uuid{}};
  275. char.Skbrief.parse $uuid $skillID;
  276. xtt.Send {#response R:skbrief-begin-$uuid;skbrief $skillID;response R:skbrief-end-$uuid#};
  277. };
  278. ///=== {
  279. // #@ char.SkillID <技能中文名称>
  280. // 返回技能的 ID。支持且仅支持所有玩家 skills 命令中可以看到的技能。
  281. // };
  282. #func {char.SkillID} {
  283. #local skill {%1};
  284. #return {$char[Skills][$skill][code]};
  285. };
  286. ///=== {
  287. // #@ char.SkillLimit [<技能中文名称>]
  288. // 如果指定了技能名称,则返回该技能所能达到的技能上限。
  289. // 如果没有指定或者技能不存在,则返回本人的武功技能上限。
  290. // 如果技能上限获取失败,默认值为基本内功的上限,如果基本内功上限也没有获取到,则默认为 1。
  291. // };
  292. #func {char.SkillLimit} {
  293. #local skill {%1};
  294. #local limit {@defaultNum{$char-skill-limit;@defaultNum{$char[Skills][基本内功][limit];1}}};
  295. #local limit {@defaultNum{$char[Skills][$skill][limit];$limit}};
  296. #return $limit;
  297. };
  298. ///=== {
  299. // #@ char.SkillType <技能中文名称>
  300. // 返回该技能的技能类别。
  301. // 常见的技能类别有:
  302. // - 基本功夫
  303. // - 特殊功夫
  304. // - 基本知识
  305. // - 职业技能
  306. // };
  307. #func {char.SkillType} {
  308. #local skill {%1};
  309. #return {$char[Skills][$skill][type]};
  310. };
  311. ///=== {
  312. // #@ char.SkillLevel <技能中文名称>
  313. // 返回该技能的当前等级。没学会的技能等级为 0。
  314. // };
  315. #func {char.SkillLevel} {
  316. #local skill {%1};
  317. #if { "$char[Skills][$skill]" == "" } {
  318. #return 0;
  319. };
  320. #return $char[Skills][$skill][level];
  321. };
  322. ///=== {
  323. // #@ char.IsSkillEnabled <技能中文名称>
  324. // 判断该技能是否被激发。这里的技能名称既可以是基本功夫,也可以是特殊功夫。
  325. // };
  326. #func {char.IsSkillEnabled} {
  327. #local skill {%1};
  328. #if { "$char[Skills][$skill]" == "" } {
  329. #return 0;
  330. };
  331. #if { "$char[Skills][$skill][jifa-to]" == "" } {
  332. #return 0;
  333. };
  334. #return 1;
  335. };
  336. ///=== {
  337. // #@ char.GetJifaSkill <混合参数>
  338. // 提供技能激发情况查询。
  339. // 共分为三种情况:
  340. // 1,输入参数为基本技能,输出对应的特殊技能名称。如果未激发则为空
  341. // 2,输入参数为特殊技能,输出对应的基本技能名称。结果可能为多个。如果未激发则为空
  342. // 3,输入参数为激发类型,则输出对应的基本技能名称。又分为以下两种情形:
  343. // (1),输入参数为常用拳脚或者常用兵器,则输出相应的基本技能名称。
  344. // 由于存在互备的情形,因此结果是一个字符串列表,可能包含多个技能名称
  345. // (2),其它内功、躲闪、招架及武功种类,则输出对应的特殊技能名称
  346. // };
  347. #func {char.GetJifaSkill} {
  348. #local arg {%1};
  349. #local skills {};
  350. #if { "$arg" == "常用{拳脚|兵器}" } {
  351. #local skill {};
  352. #foreach {*char[Skills][]} {skill} {
  353. #local elem {$char[Skills][$skill]};
  354. #if { "$elem[type]" != "基本功夫" } {
  355. #continue;
  356. };
  357. #if { "$elem[jifa-type]" == "$arg" } {
  358. #list skills add {$skill};
  359. };
  360. };
  361. #return {@slist.FromList{$skills}};
  362. };
  363. #if { "$arg" == "躲闪" } {
  364. #local arg {基本轻功};
  365. };
  366. #if { "$char[Skills][$arg][jifa-to]" != "" } {
  367. #return {$char[Skills][$arg][jifa-to]};
  368. };
  369. #local arg {基本$arg};
  370. #if {"$char[Skills][$arg][jifa-to]" != "" } {
  371. #return {$char[Skills][$arg][jifa-to]};
  372. };
  373. #else {
  374. #return {};
  375. };
  376. };
  377. ///=== {
  378. // #@ char.SkillJifaLevel <技能中文名称>
  379. // 返回技能激发等级,数据来自 jifa/enable 命令。
  380. // 如果技能未被激发,那么分两种情况:
  381. // 1. 如果输入的技能名称为基本功夫,则取 jifa 数据。
  382. 如果 jifa 数据取不到,则取技能当前等级的一半。
  383. // 2. 如果输入的技能名称为特殊功夫,则取技能的当前等级。
  384. // };
  385. #func {char.SkillJifaLevel} {
  386. #local skill {%1};
  387. #if { "$char[Skills][$skill]" == "" } {
  388. #return 0;
  389. };
  390. #local level {$char[Skills][$skill][level]};
  391. #if { "$skill" == "基本%*" } {
  392. #math level {$char[Skills][$skill][level] / 2};
  393. };
  394. #return {@defaultNum{$char[Skills][$skill][jifa-level];$level}};
  395. };
  396. ///=== {
  397. // #@ char.CanLianxi [<基本武功>]
  398. // 如果某项武功可以练习,则返回真,否则返回假。
  399. // 如果省略参数,则默认为基本招架。
  400. // 注意: 这里不考虑游戏特定的限制,只做简单的等级比较。
  401. // };
  402. #func {char.CanLianxi} {
  403. #local skill {@default{%1;基本招架}};
  404. #if { "$skill" != "基本%*" || "$skill" == "基本内功" } {
  405. #return 0;
  406. };
  407. #local baseLvl {@math.Floor{@char.SkillLevel{$skill}}};
  408. #local skill {@char.GetJifaSkill{$skill}};
  409. #local level {@math.Floor{@char.SkillLevel{$skill}}};
  410. #if { "$skill" == "" || $baseLvl == 0 || $level == 0 } {
  411. #return 0;
  412. };
  413. #if { $baseLvl <= $level } {
  414. #return 0;
  415. };
  416. #return 0;
  417. };
  418. ///=== {
  419. // #@ char.CanLingwu [<基本武功>]
  420. // 如果某项武功可以领悟,则返回真,否则返回假。
  421. // 如果省略参数,则默认为基本内功。
  422. // };
  423. #func {char.CanLingwu} {
  424. #local skill {@default{%1;基本内功}};
  425. #if { "$skill" != "基本%*" } {
  426. #return 0;
  427. };
  428. #local baseLvl {@math.Floor{@char.SkillLevel{$skill}}};
  429. #local skill {@char.GetJifaSkill{$skill}};
  430. #local level {@math.Floor{@char.SkillLevel{$skill}}};
  431. #local limit {@math.Floor{@char.SkillLimit{$skill}}};
  432. #if { "$skill" == "" || $baseLvl == 0 || $level == 0 } {
  433. #return 0;
  434. };
  435. #if { $baseLvl > $level || $baseLvl >= $limit } {
  436. #return 0;
  437. };
  438. #return 1;
  439. };
  440. ///=== {
  441. // #@ char.CanXiulian [<内功中文名称>]
  442. // 如果角色拥有足够的潜能(暂定为 10w),并且内功等级尚未达到上限,则返回真,否则返回假。
  443. // 可选的内功名称参数用来指定具体的内功,如果省略则取当前激发的内功。
  444. // };
  445. #func {char.CanXiulian} {
  446. #local force {%1};
  447. #if { "$force" == "" } {
  448. #local force {@char.GetJifaSkill{基本内功}};
  449. };
  450. #if { "$force" == "" } {
  451. #return 0;
  452. };
  453. #local level {@math.Floor{@char.SkillLevel{$force}}};
  454. #local limit {@math.Floor{@char.SkillLimit{$force}}};
  455. #if { @defaultNum{$char[HP][潜能];0} < 100000 } {
  456. #return 0
  457. };
  458. #if { $level < 100 || $level >= $limit } {
  459. #return 0;
  460. };
  461. #return 1;
  462. };
  463. #action {^你的「%*」进步了!$E} {
  464. #local name {%1};
  465. #if { "$char[Skills][$name]" == "" } {
  466. #return;
  467. };
  468. #local level {@math.Floor{@char.SkillLevel{$name}}};
  469. #local level {@math.Eval{$level + 1}};
  470. #local limit {@char.SkillLimit{$name}};
  471. fullskLog @buffer.RawLine{} 当前进度: $level / $limit;
  472. #line sub var #delay char.skills.update.level {skbrief $char[Skills][$name][code]} 0.1;
  473. #if { "$name" == "基本内功" || "@char.GetJifaSkill{$name}" == "基本内功" } {
  474. #delay char.skills.update.neili {hp -neili} 0.1;
  475. };
  476. } {9.1};