backpack.tin 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598
  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_backpack[META] {
  10. {NAME} {背包管理}
  11. {DESC} {解析背包内容,识别物品信息,并储存到变量。并提供必要的整理工具}
  12. {AUTHOR} {担子炮}
  13. {NOTE} {本文件属于 PaoTin++ 的一部分}
  14. };
  15. /*
  16. i2 格式:
  17. 你身上带著下列这些东西(负重 27%):
  18. 九十一两白银(Silver)
  19. 一粒牛黃血竭丹(Xuejie dan)
  20. 二个竹壶(Zhuhu)
  21. 三块干粮(Gan liang)
  22. 大砍刀(Dakan dao)
  23. 青锋剑(Qingfeng sword)
  24. 北侠战袍(Pkuxkx zhanpao)
  25. 北侠战甲(Pkuxkx zhanjia)
  26. 北侠战衣(Pkuxkx zhanyi)
  27. 北侠战盔(Pkuxkx zhankui)
  28. 北侠战靴(Pkuxkx zhanxue)
  29. 锦囊(Jin nang)
  30. -------------------------------------------
  31. 你左手拿着:大砍刀(Dakan dao)
  32. 你右手拿着:青锋剑(Qingfeng sword)
  33. -------------------------------------------
  34. 你身上穿着:
  35. 北侠战袍(Pkuxkx zhanpao)
  36. 北侠战甲(Pkuxkx zhanjia)
  37. 北侠战衣(Pkuxkx zhanyi)
  38. 北侠战盔(Pkuxkx zhankui)
  39. 北侠战靴(Pkuxkx zhanxue)
  40. 锦囊(Jin nang)
  41. */
  42. VAR {所有随身物品,包括武器装备食物饮料,但不包括包袱里的内容} char.Item {};
  43. VAR {现金(银票/黄金/白银/铜板)} char.Cash {};
  44. VAR {已经穿戴的装备} char.Wear {};
  45. VAR {已经装备的武器} char.Wield {};
  46. VAR {没有穿戴的装备} char.Equip {};
  47. VAR {已经 autoload 的装备} char.Autoload {};
  48. VAR {背包里所有物品的 ID} char.ItemID {};
  49. VAR {包袱及其内容} char.Bag {};
  50. VAR {背包内容是否已经脏了} char.backpack.IsDirty {1};
  51. VAR {背包总负重(百分比)} char.backpack.Percent {0};
  52. VAR {背包总负重(重量)} char.backpack.Weight {0};
  53. VAR {背包总负重(数量)} char.backpack.Number {0};
  54. event.Define {char/i2} {无参} {$MODULE} {i2 命令运行完毕,背包数据已更新};
  55. event.Define {char/id} {无参} {$MODULE} {id 命令运行完毕,背包数据已更新};
  56. event.Define {char/backpack} {无参} {$MODULE} {i2 和 id 命令运行完毕,背包数据已更新};
  57. event.Define {char/bag} {无参} {$MODULE} {look bag 命令运行完毕,背包数据已更新};
  58. #func {basic_char_backpack.Init} {
  59. load-config affix;
  60. load-config loots;
  61. #return true;
  62. };
  63. #alias {char.reset.i2} {
  64. #var char.Item {};
  65. #var char.Cash {};
  66. #var char.Wear {};
  67. #var char.Wield {};
  68. #var char.Equip {};
  69. #var char.Autoload {};
  70. #var char.ItemID {};
  71. };
  72. #alias {char.reset.bag} {
  73. #local id {%1};
  74. #if { "$id" != "%+1..d" } {
  75. #return;
  76. };
  77. #var char.Bag[$id] {};
  78. };
  79. #var 汉字数词 {(?:零|一|二|三|四|五|六|七|八|九|十|百|千|万|亿)+};
  80. #var 汉字量词 {(?:本|块|碗|件|册|柄|把|根|枚|个|粒|味|0)};
  81. #var 词缀修饰 {(?:[^ ][^ ])+};
  82. #alias {char.backpack.set} {
  83. #local type {%1};
  84. #local amount {%2};
  85. #local unit {%3};
  86. #local name {%4};
  87. #local id {@str.ToLower{%5}};
  88. #if { "$char.backpack.currentType" == "穿戴" } {
  89. #local type {Wear};
  90. };
  91. #elseif { "$char.backpack.currentType" == "包袱" } {
  92. #local type {Bag[$char.backpack.currentBag]};
  93. };
  94. #if { "$type" != "{Item|Cash|Wear|Wield|Equip|Gem|Bag\[\d+\]}" } {
  95. #return;
  96. };
  97. #if { "$type" == "Item" } {
  98. #if { "$amount" == "" && "$name" == "{${汉字数词}}%+1u%+1..u" } {
  99. #local new {$name};
  100. #replace new {^{${汉字数词}}%+1u%+1..u$} {
  101. {amount} {&1}
  102. {unit} {&2}
  103. {name} {&3}
  104. };
  105. #local new {$new};
  106. #local keys {@table.Keys{gLootPool;{$new[name]/$id}}};
  107. #local count {@sset.Size{$keys}};
  108. #if { $count == 0 } {
  109. warnLog 疑似未知掉落物「$new[name]/$id」,单位为「$new[unit]」,请确认。;
  110. };
  111. #elseif { $count == 1 } {
  112. #if { "$gLootPool[$keys][unit]" == "$new[unit]" } {
  113. #local name {$new[name]};
  114. #local unit {$new[unit]};
  115. #local amount {$new[amount]};
  116. };
  117. #else {
  118. warnLog 掉落物「$new[name]/$id」的单位「$new[unit]」与数据库中($gLootPool[$keys][unit])不符,请确认。;
  119. };
  120. };
  121. };
  122. };
  123. #if { "$amount" == "" } {
  124. #local amount {1};
  125. };
  126. #else {
  127. #local amount {@math.ParseCN{$amount}};
  128. };
  129. #local key {$name/$id};
  130. #if { "$type" == "Wear" } {
  131. #if { "$char.Wear[$key]" != "" } {
  132. #local amount {@math.Eval{$char.Wear[$key][amount] + 1}};
  133. };
  134. };
  135. #local value {
  136. {name} {$name}
  137. {id} {@str.ToLower{$id}}
  138. {amount} {$amount}
  139. };
  140. #if { "$gLootPool[$key]" != "" } {
  141. #local field {};
  142. #foreach {kind} {field} {
  143. #local value[$field] {$gLootPool[$key][$field]};
  144. };
  145. };
  146. #var {char.${type}[$key]} {$value};
  147. #if { "$type" == "{Equip|Cash}" } {
  148. #var {char.Item[$key]} {$value};
  149. };
  150. };
  151. #action {^这是一个粗布做的大包袱,里面可以装很多东西。$E} {
  152. #local bag {@ga.ThisCmd{}};
  153. #replace bag {^%* bag%s%d$} {&3};
  154. char.backpack.parse {bag} {$bag};
  155. };
  156. #action {^你身上带著下列这些东西(负重 %d%):$E} {
  157. #var char.backpack.IsDirty 0;
  158. #var char.backpack.Percent {%1};
  159. char.backpack.parse i2;
  160. };
  161. #alias {char.backpack.parse} {
  162. #local where {%1};
  163. #local index {%2};
  164. #class ParseItems open;
  165. #var char.backpack.currentType {随身};
  166. #var char.backpack.currentBag {1};
  167. #if { "$where" == "i2" } {
  168. char.reset.i2;
  169. };
  170. #elseif { "$where" == "bag" } {
  171. #local index {@defaultNum{$index;1}};
  172. #var char.backpack.currentType {包袱};
  173. #var char.backpack.currentBag {$index};
  174. char.reset.bag $index;
  175. };
  176. #nop 九十一两白银(Silver);
  177. #action {^{?:(?:(${汉字数词})(两|文|张))?}{黄金|白银|铜板|一千两银票}(%*)$} {
  178. char.backpack.set {Cash} {%%1} {%%2} {%%3} {%%4};
  179. } {4.2};
  180. #action {^{?:(?:(${汉字数词})件)?}{${全职业装}}之{${职业部位}}(%*)$} {
  181. char.backpack.set {Equip} {%%1} {件} {%%2之%%3} {%%4};
  182. } {4.2};
  183. #action {^{?:(?:(${汉字数词})件)?}{${随机装备}}之{${随机部位}}(%*)$} {
  184. char.backpack.set {Equip} {%%1} {件} {%%2之%%3} {%%4};
  185. } {4.2};
  186. #action {^{?:(?:(${汉字数词})件)?}{${随机首饰}}之{${首饰部位}}(%*)$} {
  187. char.backpack.set {Equip} {%%1} {件} {%%2之%%3} {%%4};
  188. } {4.2};
  189. #action {^{?:(?:(${汉字数词})件)?}{${江湖套装}}%S(%*)$} {
  190. char.backpack.set {Equip} {%%1} {件} {%%2之%%3} {%%4};
  191. } {4.2};
  192. #action {^{?:(?:(${汉字数词})柄)?}{${随机武器}}之{${武器种类}}(%*)$} {
  193. char.backpack.set {Equip} {%%1} {柄} {%%2之%%3} {%%4};
  194. } {4.2};
  195. #nop 镶嵌了宝石的随机装备或职业装备;
  196. #action {^{?:(?:(${汉字数词})(柄|件))?}%S %S之%S(%*)$} {
  197. char.backpack.set {Equip} {%%1} {%%2} {%%3 %%4之%%5} {%%6};
  198. } {4.2};
  199. #nop 镶嵌了宝石的江湖套装;
  200. #action {^{?:(${汉字数词})(${汉字量词})|}%S %S(%*)$} {
  201. char.backpack.set {Equip} {%%1} {%%2} {%%3 %%4} {%%5};
  202. } {4.3};
  203. #action {^{?:(?:(${汉字数词})颗)?}$GEM(%*)$} {
  204. char.backpack.set {Gem} {%%1} {颗} {%%2} {%%3};
  205. } {4.2};
  206. #nop 其它物品;
  207. #action {^{?:(${汉字数词})(${汉字量词})|}%S(%*)$} {
  208. char.backpack.set {Item} {%%1} {%%2} {%%3} {%%4};
  209. } {4.3};
  210. #nop 其它物品;
  211. #action {^%S(%*)$} {
  212. char.backpack.set {Item} {一} {个} {%%1} {%%2};
  213. } {4.4};
  214. #nop 你左手拿着:大砍刀(Dakan dao);
  215. #nop 你右手拿着:青锋剑(Qingfeng sword);
  216. #action {^你{左手|右手}拿着:%*(%*)$} {
  217. #local hand {%%1};
  218. #local item {%%2};
  219. #local id {@str.ToLower{%%3}};
  220. #var char.Wield[$item/$hand/$id] {
  221. {hand} {$hand}
  222. {item} {$item}
  223. {id} {$id}
  224. };
  225. } {4.1};
  226. #action {^你手里什么也没拿$} {
  227. #var char.Wield {};
  228. };
  229. #action {^你身上穿着:$} {
  230. #var char.backpack.currentType {穿戴};
  231. };
  232. event.HandleOnce GA {backpack/i2} {char/backpack} {
  233. event.Emit char/i2;
  234. #class ParseItems kill;
  235. #0
  236. };
  237. #class ParseItems close;
  238. };
  239. #action {^你身上携带物品的别称如下 :$E} {
  240. #class ParseItems open;
  241. #var {char.ItemID} {};
  242. #action {^%*%s = %*{|ID=char/ItemID}$} {
  243. #local name {@str.Trim{%%1}};
  244. #local ids {@str.Split{{%%3};{, }}};
  245. #local uuid {};
  246. #local type {};
  247. #local id {};
  248. #foreach {$ids} {id} {
  249. #if { "$id" == "my %*" } {
  250. #replace {id} {my } {};
  251. #local type {$id};
  252. #continue;
  253. };
  254. #if { "$id" == "{am|wp}_%d" } {
  255. #local uuid {$id};
  256. #continue;
  257. };
  258. #local amount {1};
  259. #if { &char.ItemID[$name/$id] > 0 } {
  260. #local amount {@math.Eval{ $char.ItemID[$name/$id][amount] + 1 }};
  261. };
  262. #var {char.ItemID[$name/$id]} {
  263. {name} {$name}
  264. {id} {$id}
  265. {amount} {$amount}
  266. {ids} {$ids}
  267. };
  268. };
  269. #if { "$uuid" != "" } {
  270. #var {char.Autoload[$name/$uuid/$type]} {
  271. {name} {$name}
  272. {type} {$type}
  273. {uuid} {$uuid}
  274. {ids} {$ids}
  275. };
  276. };
  277. } {4};
  278. event.HandleOnce GA {backpack/id} {char/backpack} {
  279. event.Emit char/id;
  280. #class ParseItems kill;
  281. #0
  282. };
  283. #class ParseItems close;
  284. };
  285. ///=== {
  286. // ## char.backpack.Refresh [<是否强制刷新>]
  287. // 刷新背包数据。
  288. // 默认会检测 char.backpack.IsDirty 变量,除非必要否则不向服务器发送任何命令。
  289. // 但用户可以传递参数 true 以启用强制刷新。
  290. // };
  291. #alias {char.backpack.Refresh} {
  292. #local force {@default{%1;false}};
  293. #if { !@isTrue{$force} && !$char.backpack.IsDirty } {
  294. warnLog 背包数据未发生变更,无需刷新。;
  295. #return;
  296. };
  297. #class char.backpack.refresh open;
  298. #gag {^%*{|ID=char/backpack/refresh}$};
  299. #action {^等等,系统喘气中......{|ID=char/backpack/Refresh}$} {
  300. errLog 物品 ID 数据刷新失败,稍后即将重试。;
  301. #ungag {^%*{|ID=char/backpack/refresh}$};
  302. #delay char.backpack.refresh {
  303. #class char.backpack.refresh assign #gag {^%*{|ID=char/backpack/refresh}$};
  304. id;
  305. } 10;
  306. };
  307. #nop i2 命令不会失败,但 id 命令有 CD,会失败。;
  308. i2; id;
  309. event.HandleOnce {char/id} {char.backpack.refresh} {char/backpack} {
  310. okLog 背包数据已刷新。;
  311. #class char.backpack.refresh kill;
  312. event.Emit char/backpack;
  313. #0
  314. };
  315. #undelay char.backpack.refresh;
  316. #class char.backpack.refresh close;
  317. };
  318. ///=== {
  319. // #@ char.backpack.Query <范围> <ID 或名称>
  320. // 查询角色是否携带有某样物品。如果有,则返回 ID 和名称;否则返回空串。
  321. // 查询范围:
  322. // Item: 所有物品(但不包括包袱里的内容)
  323. // Cash: 现金
  324. // Wear: 穿戴
  325. // Wield: 手持的装备(武器或盾牌)
  326. // Equip: 携带的装备
  327. // Gem: 背包里的宝石
  328. // Autoload: Autoload 的装备
  329. // ItemID: id 命令看到的数据
  330. // BagN: 包袱里的物品,其中 N 表示是包袱的序号,省略表示 Bag1
  331. // };
  332. #func {char.backpack.Query} {
  333. #local range {%1};
  334. #local key {%2};
  335. #local func {@default{%3;char.backpack.Query}};
  336. #if { "$range" != "{Item|Cash|Wear|Wield|Equip|Gem|Autoload|ItemID|Bag\s*\d+}" } {
  337. xtt.Usage $func;
  338. #return;
  339. };
  340. #local container {};
  341. #if { "$range" == "Bag%s%d" } {
  342. #local container {$range};
  343. #replace container {^Bag%s%d$} {&2};
  344. #local container {@defaultNum{$container;1}};
  345. #local container {$char.Bag[$container]};
  346. };
  347. #else {
  348. #local container {${char.$range}};
  349. };
  350. #local items {};
  351. #local var {};
  352. #local items {@table.Keys{container;{$key/%*}}};
  353. #if { "$items" == "" } {
  354. #local items {@table.Keys{container;{%*/$key}}};
  355. };
  356. #return {$items};
  357. };
  358. ///=== {
  359. // #@ char.backpack.Has <范围> <ID 或名称>
  360. // 查询角色是否携带有某样物品。如果有,则返回真,否则返回假。
  361. // 查询范围参见 HELP char.backpack.Query。
  362. // };
  363. #func {char.backpack.Has} {
  364. #local items {@char.backpack.Query{{%1};{%2}}};
  365. #if { "$items" == "" } {
  366. #return 0;
  367. };
  368. #else {
  369. #return 1;
  370. };
  371. };
  372. ///=== {
  373. // #@ char.backpack.Amount <范围> <名称或/和 ID>
  374. // 查询角色是否携带有某样物品。如果有,则返回其数量,否则返回 0。
  375. // 查询范围参见 HELP char.backpack.Query。
  376. // };
  377. #func {char.backpack.Amount} {
  378. #local range {%1};
  379. #local key {%2};
  380. #local container {};
  381. #if { "$range" == "Bag%s%d" } {
  382. #local container {$range};
  383. #replace container {^Bag%s%d$} {&2};
  384. #local container {@defaultNum{$container;1}};
  385. #local container {$char.Bag[$container]};
  386. };
  387. #else {
  388. #local container {${char.$range}};
  389. };
  390. #local info {$container[$key]};
  391. #if { "$info" == "" } {
  392. #local items {@char.backpack.Query{{$range};{$key}}};
  393. #if { "$items" == "" } {
  394. #return 0;
  395. };
  396. #local count {@slist.Size{$items}};
  397. #if { $count > 1 } {
  398. errLog 名称或 ID 不唯一,请精确指定,格式为:「蛇床子/shechuang zi」。;
  399. #return -1;
  400. };
  401. #return @char.backpack.Amount{$range;$items};
  402. };
  403. #return {@defaultNum{$info[amount];1}};
  404. };
  405. ///=== {
  406. // ## char.backpack.SellAll
  407. // 把身上的低价值物品全部卖掉。
  408. // };
  409. #alias {char.backpack.SellAll} {
  410. #if { $char.backpack.IsDirty } {
  411. char.backpack.Refresh;
  412. event.HandleOnce {char/backpack} {char.backpack.SellAll} {char/backpack} {char.backpack.SellAll};
  413. #return;
  414. };
  415. #class char.backpack.SellAll open;
  416. #var char.backpack.SellAll.index {&char.Item[]};
  417. #alias {char.backpack.SellAll.do} {
  418. #if { $char.backpack.SellAll.index == 0 } {
  419. okLog 背包里的所有杂物都已经卖完了。;
  420. char.backpack.Refresh true;
  421. #undelay char.backpack.SellAll.do;
  422. #class char.backpack.SellAll kill;
  423. #return;
  424. };
  425. #if { @char.IsBusy{} } {
  426. #delay char.backpack.SellAll.do {char.backpack.SellAll.do} 1;
  427. #return;
  428. };
  429. #local item {$char.Item[+$char.backpack.SellAll.index]};
  430. math.Inc char.backpack.SellAll.index -1;
  431. #local attr {$gLootPool[$item[name]/$item[id]]};
  432. #if { "$attr[value]" == "sell" } {
  433. #if { $item[amount] == 1 } {
  434. sell $item[id];
  435. };
  436. #else {
  437. sell $item[id] for $item[amount];
  438. };
  439. #delay char.backpack.SellAll.do {char.backpack.SellAll.do} 1;
  440. #return;
  441. };
  442. #delay char.backpack.SellAll.do {char.backpack.SellAll.do} 0;
  443. };
  444. char.backpack.SellAll.do;
  445. #class char.backpack.SellAll close;
  446. };
  447. ///=== {
  448. // ## char.backpack.DropAll
  449. // 把身上的不能卖的低价值物品全部扔掉。
  450. // };
  451. #alias {char.backpack.DropAll} {
  452. #if { $char.backpack.IsDirty } {
  453. char.backpack.Refresh;
  454. event.HandleOnce {char/backpack} {char.backpack.DropAll} {char/backpack} {char.backpack.DropAll};
  455. #return;
  456. };
  457. #class char.backpack.DropAll open;
  458. #var char.backpack.DropAll.index {&char.Item[]};
  459. #alias {char.backpack.DropAll.do} {
  460. #if { $char.backpack.DropAll.index == 0 } {
  461. okLog 背包里的所有杂物都已经扔完了。;
  462. char.backpack.Refresh true;
  463. #undelay char.backpack.DropAll.do;
  464. #class char.backpack.DropAll kill;
  465. #return;
  466. };
  467. #if { @char.IsBusy{} } {
  468. #delay char.backpack.DropAll.do {char.backpack.DropAll.do} 1;
  469. #return;
  470. };
  471. #local item {$char.Item[+$char.backpack.DropAll.index]};
  472. math.Inc char.backpack.DropAll.index -1;
  473. #local attr {$gLootPool[$item[name]/$item[id]]};
  474. #if { "$attr[value]" == "drop" } {
  475. #if { $item[amount] == 1 } {
  476. drop $item[id];
  477. };
  478. #elseif { $item[amount] <= 10 } {
  479. do $item[amount] drop $item[id];
  480. };
  481. #else {
  482. #$item[amount] drop $item[id];
  483. };
  484. #delay char.backpack.DropAll.do {char.backpack.DropAll.do} 1;
  485. #return;
  486. };
  487. #delay char.backpack.DropAll.do {char.backpack.DropAll.do} 0;
  488. };
  489. char.backpack.DropAll.do;
  490. #class char.backpack.DropAll close;
  491. };
  492. #action {^你放下手中的%*。$E} {#var char.backpack.IsDirty 1};
  493. #action {^你举起%*之盾遮护自身。$E} {#var char.backpack.IsDirty 1};
  494. #action {^你装备%*做武器。$E} {#var char.backpack.IsDirty 1};
  495. #action {^你打开盲盒,发现了%*。$E} {#var char.backpack.IsDirty 1};
  496. #action {^你重新加载了%*等%*件装备。$E} {#var char.backpack.IsDirty 1};
  497. #action {^│你共携带%*件器物,负重约%*斤,} {
  498. #var char.backpack.Number {@math.ParseCN{%1}};
  499. #var char.backpack.Weight {@math.ParseCN{%2}};
  500. };