This repository has been archived by the owner on Aug 9, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 20
/
init.lua
2513 lines (2020 loc) · 59.9 KB
/
init.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
craftguide = {}
-- Caches
local pdata = {}
local init_items = {}
local searches = {}
local recipes_cache = {}
local usages_cache = {}
local fuel_cache = {}
local replacements = {fuel = {}}
local toolrepair
local progressive_mode = core.settings:get_bool "craftguide_progressive_mode"
local http = core.request_http_api()
local singleplayer = core.is_singleplayer()
local reg_items = core.registered_items
local reg_nodes = core.registered_nodes
local reg_craftitems = core.registered_craftitems
local reg_tools = core.registered_tools
local reg_entities = core.registered_entities
local reg_aliases = core.registered_aliases
local log = core.log
local after = core.after
local clr = core.colorize
local parse_json = core.parse_json
local write_json = core.write_json
local chat_send = core.chat_send_player
local show_formspec = core.show_formspec
local globalstep = core.register_globalstep
local on_shutdown = core.register_on_shutdown
local get_players = core.get_connected_players
local get_craft_result = core.get_craft_result
local translate = minetest.get_translated_string
local on_joinplayer = core.register_on_joinplayer
local get_all_recipes = core.get_all_craft_recipes
local register_command = core.register_chatcommand
local get_player_by_name = core.get_player_by_name
local slz, dslz = core.serialize, core.deserialize
local on_mods_loaded = core.register_on_mods_loaded
local on_leaveplayer = core.register_on_leaveplayer
local get_player_info = core.get_player_information
local on_receive_fields = core.register_on_player_receive_fields
local ESC = core.formspec_escape
local S = core.get_translator "craftguide"
local ES = function(...)
return ESC(S(...))
end
local maxn, sort, concat, copy, insert, remove =
table.maxn, table.sort, table.concat, table.copy,
table.insert, table.remove
local sprintf, find, gmatch, match, sub, split, upper, lower =
string.format, string.find, string.gmatch, string.match,
string.sub, string.split, string.upper, string.lower
local min, max, floor, ceil, abs = math.min, math.max, math.floor, math.ceil, math.abs
local pairs, ipairs, next, type, setmetatable, tonum =
pairs, ipairs, next, type, setmetatable, tonumber
local vec_add, vec_mul = vector.add, vector.multiply
local ROWS = 9
local LINES = 10
local IPP = ROWS * LINES
local MAX_FAVS = 6
local ITEM_BTN_SIZE = 1.1
-- Progressive mode
local POLL_FREQ = 0.25
local HUD_TIMER_MAX = 1.5
local MIN_FORMSPEC_VERSION = 4
local PNG = {
bg = "craftguide_bg.png",
bg_full = "craftguide_bg_full.png",
search = "craftguide_search.png",
prev = "craftguide_next.png^\\[transformFX",
next = "craftguide_next.png",
arrow = "craftguide_arrow.png",
trash = "craftguide_trash.png",
sort_az = "craftguide_sort.png",
sort_za = "craftguide_sort2.png",
compress = "craftguide_compress.png",
fire = "craftguide_fire.png",
fire_anim = "craftguide_fire_anim.png",
book = "craftguide_book.png",
sign = "craftguide_sign.png",
cancel = "craftguide_cancel.png",
export = "craftguide_export.png",
slot = "craftguide_slot.png",
tab = "craftguide_tab.png",
furnace_anim = "craftguide_furnace_anim.png",
cancel_hover = "craftguide_cancel.png^\\[brighten",
search_hover = "craftguide_search.png^\\[brighten",
export_hover = "craftguide_export.png^\\[brighten",
trash_hover = "craftguide_trash.png^\\[brighten",
compress_hover = "craftguide_compress.png^\\[brighten",
sort_az_hover = "craftguide_sort.png^\\[brighten",
sort_za_hover = "craftguide_sort2.png^\\[brighten",
prev_hover = "craftguide_next_hover.png^\\[transformFX",
next_hover = "craftguide_next_hover.png",
tab_hover = "craftguide_tab_hover.png",
}
local fs_elements = {
box = "box[%f,%f;%f,%f;%s]",
label = "label[%f,%f;%s]",
image = "image[%f,%f;%f,%f;%s]",
button = "button[%f,%f;%f,%f;%s;%s]",
tooltip = "tooltip[%f,%f;%f,%f;%s]",
item_image = "item_image[%f,%f;%f,%f;%s]",
bg9 = "background9[%f,%f;%f,%f;%s;false;%u]",
model = "model[%f,%f;%f,%f;%s;%s;%s;%s;%s;true;%s]",
image_button = "image_button[%f,%f;%f,%f;%s;%s;%s]",
animated_image = "animated_image[%f,%f;%f,%f;;%s;%u;%u]",
scrollbar = "scrollbar[%f,%f;%f,%f;horizontal;%s;%u]",
item_image_button = "item_image_button[%f,%f;%f,%f;%s;%s;%s]",
}
local styles = sprintf([[
style_type[label,field;font_size=16]
style_type[image_button;border=false;sound=craftguide_click]
style_type[item_image_button;border=false;bgimg_hovered=%s;sound=craftguide_click]
style[filter;border=false]
style[cancel;fgimg=%s;fgimg_hovered=%s;content_offset=0]
style[search;fgimg=%s;fgimg_hovered=%s;content_offset=0]
style[trash;fgimg=%s;fgimg_hovered=%s;content_offset=0;sound=craftguide_delete]
style[sort_az;fgimg=%s;fgimg_hovered=%s;content_offset=0]
style[sort_za;fgimg=%s;fgimg_hovered=%s;content_offset=0]
style[compress;fgimg=%s;fgimg_hovered=%s;content_offset=0]
style[prev_page;fgimg=%s;fgimg_hovered=%s]
style[next_page;fgimg=%s;fgimg_hovered=%s]
style[prev_recipe;fgimg=%s;fgimg_hovered=%s]
style[next_recipe;fgimg=%s;fgimg_hovered=%s]
style[prev_usage;fgimg=%s;fgimg_hovered=%s]
style[next_usage;fgimg=%s;fgimg_hovered=%s]
style[guide_mode,inv_mode;fgimg_hovered=%s;noclip=true;content_offset=0;sound=craftguide_tab]
style[pagenum,no_item,no_rcp;border=false;font=bold;font_size=18;content_offset=0]
style[craft_rcp,craft_usg;border=false;noclip=true;font_size=16;sound=craftguide_craft;
bgimg=craftguide_btn9.png;bgimg_hovered=craftguide_btn9_hovered.png;
bgimg_pressed=craftguide_btn9_pressed.png;bgimg_middle=4,6]
]],
PNG.slot,
PNG.cancel, PNG.cancel_hover,
PNG.search, PNG.search_hover,
PNG.trash, PNG.trash_hover,
PNG.sort_az, PNG.sort_az_hover,
PNG.sort_za, PNG.sort_za_hover,
PNG.compress, PNG.compress_hover,
PNG.prev, PNG.prev_hover,
PNG.next, PNG.next_hover,
PNG.prev, PNG.prev_hover,
PNG.next, PNG.next_hover,
PNG.prev, PNG.prev_hover,
PNG.next, PNG.next_hover,
PNG.tab_hover)
local function get_lang_code(info)
return info and info.lang_code
end
local function get_formspec_version(info)
return info and info.formspec_version or 1
end
local function outdated(name)
local fs = sprintf([[
size[7.1,1.3]
image[0,0;1,1;%s]
label[1,0;%s]
button_exit[3.1,0.8;1,1;;OK]
]],
PNG.book,
"Your Minetest client is outdated.\n" ..
"Get the latest version on minetest.net to use the Crafting Guide.")
return show_formspec(name, "craftguide", fs)
end
craftguide.group_stereotypes = {
dye = "dye:white",
wool = "wool:white",
wood = "default:wood",
tree = "default:tree",
sand = "default:sand",
glass = "default:glass",
stick = "default:stick",
stone = "default:stone",
leaves = "default:leaves",
coal = "default:coal_lump",
vessel = "vessels:glass_bottle",
flower = "flowers:dandelion_yellow",
water_bucket = "bucket:bucket_water",
mesecon_conductor_craftable = "mesecons:wire_00000000_off",
}
local group_names = {
dye = S"Any dye",
coal = S"Any coal",
sand = S"Any sand",
tree = S"Any tree",
wool = S"Any wool",
glass = S"Any glass",
stick = S"Any stick",
stone = S"Any stone",
carpet = S"Any carpet",
flower = S"Any flower",
leaves = S"Any leaves",
vessel = S"Any vessel",
wood = S"Any wood planks",
mushroom = S"Any mushroom",
["color_red,flower"] = S"Any red flower",
["color_blue,flower"] = S"Any blue flower",
["color_black,flower"] = S"Any black flower",
["color_white,flower"] = S"Any white flower",
["color_green,flower"] = S"Any green flower",
["color_orange,flower"] = S"Any orange flower",
["color_yellow,flower"] = S"Any yellow flower",
["color_violet,flower"] = S"Any violet flower",
["color_red,dye"] = S"Any red dye",
["color_blue,dye"] = S"Any blue dye",
["color_grey,dye"] = S"Any grey dye",
["color_pink,dye"] = S"Any pink dye",
["color_cyan,dye"] = S"Any cyan dye",
["color_black,dye"] = S"Any black dye",
["color_white,dye"] = S"Any white dye",
["color_brown,dye"] = S"Any brown dye",
["color_green,dye"] = S"Any green dye",
["color_orange,dye"] = S"Any orange dye",
["color_yellow,dye"] = S"Any yellow dye",
["color_violet,dye"] = S"Any violet dye",
["color_magenta,dye"] = S"Any magenta dye",
["color_dark_grey,dye"] = S"Any dark grey dye",
["color_dark_green,dye"] = S"Any dark green dye",
}
craftguide.model_alias = {
["boats:boat"] = {name = "boats:boat", drawtype = "entity"},
["carts:cart"] = {name = "carts:cart", drawtype = "entity", frames = "0,0"},
["default:chest"] = {name = "default:chest_open"},
["default:chest_locked"] = {name = "default:chest_locked_open"},
["doors:door_wood"] = {name = "doors:door_wood_a"},
["doors:door_glass"] = {name = "doors:door_glass_a"},
["doors:door_obsidian_glass"] = {name = "doors:door_obsidian_glass_a"},
["doors:door_steel"] = {name = "doors:door_steel_a"},
["xpanes:door_steel_bar"] = {name = "xpanes:door_steel_bar_a"},
}
local function err(str)
return log("error", str)
end
local function msg(name, str)
return chat_send(name, sprintf("[craftguide] %s", str))
end
local function is_num(x)
return type(x) == "number"
end
local function is_str(x)
return type(x) == "string"
end
local function true_str(str)
return is_str(str) and str ~= ""
end
local function is_table(x)
return type(x) == "table"
end
local function is_func(x)
return type(x) == "function"
end
local function is_group(item)
return sub(item, 1, 6) == "group:"
end
local function fmt(elem, ...)
return sprintf(fs_elements[elem], ...)
end
local function clean_name(item)
if sub(item, 1, 1) == ":" then
item = sub(item, 2)
end
return item
end
local function array_diff(t1, t2)
local hash = {}
for i = 1, #t1 do
local v = t1[i]
hash[v] = true
end
for i = 1, #t2 do
local v = t2[i]
hash[v] = nil
end
local diff, c = {}, 0
for i = 1, #t1 do
local v = t1[i]
if hash[v] then
c = c + 1
diff[c] = v
end
end
return diff
end
local function table_eq(T1, T2)
local avoid_loops = {}
local function recurse(t1, t2)
if type(t1) ~= type(t2) then return end
if not is_table(t1) then
return t1 == t2
end
if avoid_loops[t1] then
return avoid_loops[t1] == t2
end
avoid_loops[t1] = t2
local t2k, t2kv = {}, {}
for k in pairs(t2) do
if is_table(k) then
insert(t2kv, k)
end
t2k[k] = true
end
for k1, v1 in pairs(t1) do
local v2 = t2[k1]
if type(k1) == "table" then
local ok
for i = 1, #t2kv do
local tk = t2kv[i]
if table_eq(k1, tk) and recurse(v1, t2[tk]) then
remove(t2kv, i)
t2k[tk] = nil
ok = true
break
end
end
if not ok then return end
else
if v2 == nil then return end
t2k[k1] = nil
if not recurse(v1, v2) then return end
end
end
if next(t2k) then return end
return true
end
return recurse(T1, T2)
end
local function table_merge(t1, t2, hash)
t1 = t1 or {}
t2 = t2 or {}
if hash then
for k, v in pairs(t2) do
t1[k] = v
end
else
local c = #t1
for i = 1, #t2 do
c = c + 1
t1[c] = t2[i]
end
end
return t1
end
local function table_replace(t, val, new)
for k, v in pairs(t) do
if v == val then
t[k] = new
end
end
end
local craft_types = {}
function craftguide.register_craft_type(name, def)
if not true_str(name) then
return err "craftguide.register_craft_type(): name missing"
end
if not is_str(def.description) then
def.description = ""
end
if not is_str(def.icon) then
def.icon = ""
end
craft_types[name] = def
end
function craftguide.register_craft(def)
local width, c = 0, 0
if true_str(def.url) then
if not http then
return err(sprintf([[craftguide.register_craft(): Unable to reach %s.
No HTTP support for this mod: add it to the `secure.http_mods` or
`secure.trusted_mods` setting.]], def.url))
end
http.fetch({url = def.url}, function(result)
if result.succeeded then
local t = parse_json(result.data)
if is_table(t) then
return craftguide.register_craft(t)
end
end
end)
return
end
if not is_table(def) or not next(def) then
return err "craftguide.register_craft(): craft definition missing"
end
if #def > 1 then
for _, v in pairs(def) do
craftguide.register_craft(v)
end
return
end
if def.result then
def.output = def.result -- Backward compatibility
def.result = nil
end
if not true_str(def.output) then
return err "craftguide.register_craft(): output missing"
end
if not is_table(def.items) then
def.items = {}
end
if def.grid then
if not is_table(def.grid) then
def.grid = {}
end
if not is_table(def.key) then
def.key = {}
end
local cp = copy(def.grid)
sort(cp, function(a, b)
return #a > #b
end)
width = #cp[1]
for i = 1, #def.grid do
while #def.grid[i] < width do
def.grid[i] = def.grid[i] .. " "
end
end
for symbol in gmatch(concat(def.grid), ".") do
c = c + 1
def.items[c] = def.key[symbol]
end
else
local items, len = def.items, #def.items
def.items = {}
for i = 1, len do
items[i] = items[i]:gsub(",", ", ")
local rlen = #split(items[i], ",")
if rlen > width then
width = rlen
end
end
for i = 1, len do
while #split(items[i], ",") < width do
items[i] = items[i] .. ", "
end
end
for name in gmatch(concat(items, ","), "[%s%w_:]+") do
c = c + 1
def.items[c] = match(name, "%S+")
end
end
local item = match(def.output, "%S+")
recipes_cache[item] = recipes_cache[item] or {}
def.custom = true
def.width = width
insert(recipes_cache[item], def)
end
local recipe_filters = {}
function craftguide.add_recipe_filter(name, f)
if not true_str(name) then
return err "craftguide.add_recipe_filter(): name missing"
elseif not is_func(f) then
return err "craftguide.add_recipe_filter(): function missing"
end
recipe_filters[name] = f
end
function craftguide.set_recipe_filter(name, f)
if not is_str(name) then
return err "craftguide.set_recipe_filter(): name missing"
elseif not is_func(f) then
return err "craftguide.set_recipe_filter(): function missing"
end
recipe_filters = {[name] = f}
end
function craftguide.remove_recipe_filter(name)
recipe_filters[name] = nil
end
function craftguide.get_recipe_filters()
return recipe_filters
end
local function apply_recipe_filters(recipes, player)
for _, filter in pairs(recipe_filters) do
recipes = filter(recipes, player)
end
return recipes
end
local search_filters = {}
function craftguide.add_search_filter(name, f)
if not true_str(name) then
return err "craftguide.add_search_filter(): name missing"
elseif not is_func(f) then
return err "craftguide.add_search_filter(): function missing"
end
search_filters[name] = f
end
function craftguide.remove_search_filter(name)
search_filters[name] = nil
end
function craftguide.get_search_filters()
return search_filters
end
local function weird_desc(str)
return not true_str(str) or find(str, "\n") or not find(str, "%u")
end
local function toupper(str)
return str:gsub("%f[%w]%l", upper):gsub("_", " ")
end
local function snip(str, limit)
return #str > limit and sprintf("%s...", sub(str, 1, limit - 3)) or str
end
local function get_desc(item)
if sub(item, 1, 1) == "_" then
item = sub(item, 2)
end
local def = reg_items[item]
if def then
local desc = ItemStack(item):get_short_description()
if true_str(desc) then
desc = desc:trim()
if not find(desc, "%u") then
desc = toupper(desc)
end
return desc
elseif true_str(item) then
return toupper(match(item, ":(.*)"))
end
end
return S("Unknown Item (@1)", item)
end
local function item_has_groups(item_groups, groups)
for i = 1, #groups do
local group = groups[i]
if (item_groups[group] or 0) == 0 then return end
end
return true
end
local function extract_groups(str)
if sub(str, 1, 6) == "group:" then
return split(sub(str, 7), ",")
end
end
local function get_filtered_items(player, data)
local items, known, c = {}, 0, 0
for i = 1, #init_items do
local item = init_items[i]
local recipes = recipes_cache[item]
local usages = usages_cache[item]
recipes = #apply_recipe_filters(recipes or {}, player)
usages = #apply_recipe_filters(usages or {}, player)
if recipes > 0 or usages > 0 then
c = c + 1
items[c] = item
if data then
known = known + recipes + usages
end
end
end
if data then
data.known_recipes = known
end
return items
end
local function get_burntime(item)
return get_craft_result{method = "fuel", items = {item}}.time
end
local function cache_fuel(item)
local burntime = get_burntime(item)
if burntime > 0 then
fuel_cache[item] = {
type = "fuel",
items = {item},
burntime = burntime,
replacements = replacements.fuel[item],
}
end
end
local function show_item(def)
return def and not (def.groups.not_in_craft_guide == 1 or
def.groups.not_in_creative_inventory == 1) and
def.description and def.description ~= ""
end
local function get_usages(recipe)
local added = {}
for _, item in pairs(recipe.items) do
item = reg_aliases[item] or item
if not added[item] then
local groups = extract_groups(item)
if groups then
for name, def in pairs(reg_items) do
if not added[name] and show_item(def) and
item_has_groups(def.groups, groups) then
local usage = copy(recipe)
table_replace(usage.items, item, name)
usages_cache[name] = usages_cache[name] or {}
insert(usages_cache[name], 1, usage)
added[name] = true
end
end
elseif show_item(reg_items[item]) then
usages_cache[item] = usages_cache[item] or {}
insert(usages_cache[item], 1, recipe)
end
added[item] = true
end
end
end
local function cache_usages(item)
local recipes = recipes_cache[item] or {}
for i = 1, #recipes do
get_usages(recipes[i])
end
if fuel_cache[item] then
usages_cache[item] = table_merge(usages_cache[item] or {}, {fuel_cache[item]})
end
end
local function drop_table(name, drop)
local count_sure = 0
local drop_items = drop.items or {}
local max_items = drop.max_items
for i = 1, #drop_items do
local di = drop_items[i]
local valid_rarity = di.rarity and di.rarity > 1
if di.rarity or not max_items or
(max_items and not di.rarity and count_sure < max_items) then
for j = 1, #di.items do
local dstack = ItemStack(di.items[j])
local dname = dstack:get_name()
local dcount = dstack:get_count()
local empty = dstack:is_empty()
if not empty and (dname ~= name or
(dname == name and dcount > 1)) then
local rarity = valid_rarity and di.rarity
craftguide.register_craft{
type = rarity and "digging_chance" or "digging",
items = {name},
output = sprintf("%s %u", dname, dcount),
rarity = rarity,
tools = di.tools,
}
end
end
end
if not di.rarity then
count_sure = count_sure + 1
end
end
end
local function cache_drops(name, drop)
if true_str(drop) then
local dstack = ItemStack(drop)
local dname = dstack:get_name()
local empty = dstack:is_empty()
if not empty and dname ~= name then
craftguide.register_craft{
type = "digging",
items = {name},
output = drop,
}
end
elseif is_table(drop) then
drop_table(name, drop)
end
end
local function cache_recipes(item)
local recipes = get_all_recipes(item)
if replacements[item] then
local _recipes = {}
for k, v in ipairs(recipes or {}) do
_recipes[#recipes + 1 - k] = v
end
local shift = 0
local size_rpl = maxn(replacements[item])
local size_rcp = #_recipes
if size_rpl > size_rcp then
shift = size_rcp - size_rpl
end
for k, v in pairs(replacements[item]) do
k = k + shift
if _recipes[k] then
_recipes[k].replacements = v
end
end
recipes = _recipes
end
if recipes then
recipes_cache[item] = table_merge(recipes, recipes_cache[item] or {})
end
end
local function get_recipes(player, item)
local clean_item = reg_aliases[item] or item
local recipes = recipes_cache[clean_item]
local usages = usages_cache[clean_item]
if recipes then
recipes = apply_recipe_filters(recipes, player)
end
local no_recipes = not recipes or #recipes == 0
if no_recipes and not usages then return end
usages = apply_recipe_filters(usages, player)
local no_usages = not usages or #usages == 0
return not no_recipes and recipes or nil,
not no_usages and usages or nil
end
local function groups_to_items(groups, get_all)
if not get_all and #groups == 1 then
local group = groups[1]
local stereotype = craftguide.group_stereotypes[group]
local def = reg_items[stereotype]
if def and show_item(def) then
return stereotype
end
end
local names = {}
for name, def in pairs(reg_items) do
if show_item(def) and item_has_groups(def.groups, groups) then
if get_all then
names[#names + 1] = name
else
return name
end
end
end
return get_all and names or ""
end
local function sort_itemlist(player, az)
local inv = player:get_inventory()
local list = inv:get_list("main")
local size = inv:get_size("main")
local new_inv, stack_meta = {}, {}
for i = 1, size do
local stack = list[i]
local name = stack:get_name()
local count = stack:get_count()
local empty = stack:is_empty()
local meta = stack:get_meta():to_table()
if not empty then
if next(meta.fields) then
stack_meta[#stack_meta + 1] = stack
else
new_inv[#new_inv + 1] = sprintf("%s %u", name, count)
end
end
end
if az then
sort(new_inv)
else
sort(new_inv, function(a, b) return a > b end)
end
inv:set_list("main", new_inv)
for i = 1, #stack_meta do
inv:set_stack("main", #new_inv + i, stack_meta[i])
end
end
local function compress_items(player)
local inv = player:get_inventory()
local list = inv:get_list("main")
local size = inv:get_size("main")
local new_inv, _new_inv, stack_meta = {}, {}, {}
for i = 1, size do
local stack = list[i]
local name = stack:get_name()
local count = stack:get_count()
local empty = stack:is_empty()
local meta = stack:get_meta():to_table()
if not empty then
if next(meta.fields) then
stack_meta[#stack_meta + 1] = stack
else
new_inv[name] = new_inv[name] or 0
new_inv[name] = new_inv[name] + count
end
end
end
for name, count in pairs(new_inv) do
local stackmax = ItemStack(name):get_stack_max()
local iter = ceil(count / stackmax)
local leftover = count
for _ = 1, iter do
_new_inv[#_new_inv + 1] = sprintf("%s %u", name, min(stackmax, leftover))
leftover = leftover - stackmax
end
end
sort(_new_inv)
inv:set_list("main", _new_inv)
for i = 1, #stack_meta do
inv:set_stack("main", #_new_inv + i, stack_meta[i])
end
end
local function get_stack_max(inv, data, is_recipe, rcp)
local list = inv:get_list("main")
local size = inv:get_size("main")
local counts_inv, counts_rcp, counts = {}, {}, {}
local rcp_usg = is_recipe and "recipe" or "usage"
for _, it in pairs(rcp.items) do
counts_rcp[it] = (counts_rcp[it] or 0) + 1
end
data.export_counts[rcp_usg] = {}
data.export_counts[rcp_usg].rcp = counts_rcp
for i = 1, size do
local stack = list[i]
if not stack:is_empty() then
local item = stack:get_name()
local count = stack:get_count()
for name in pairs(counts_rcp) do
if is_group(name) then
local def = reg_items[item]
if def then
local groups = extract_groups(name)
if item_has_groups(def.groups, groups) then
counts_inv[name] = (counts_inv[name] or 0) + count
end
end
end
end
counts_inv[item] = (counts_inv[item] or 0) + count
end
end
data.export_counts[rcp_usg].inv = counts_inv
for name in pairs(counts_rcp) do
counts[name] = floor((counts_inv[name] or 0) / (counts_rcp[name] or 0))
end
local max_stacks = math.huge
for _, count in pairs(counts) do
if count < max_stacks then
max_stacks = count
end
end