diff options
Diffstat (limited to 'ch_core/creative_inventory.lua')
-rw-r--r-- | ch_core/creative_inventory.lua | 1037 |
1 files changed, 1037 insertions, 0 deletions
diff --git a/ch_core/creative_inventory.lua b/ch_core/creative_inventory.lua new file mode 100644 index 0000000..91b623d --- /dev/null +++ b/ch_core/creative_inventory.lua @@ -0,0 +1,1037 @@ +ch_core.open_submod("creative_inventory", {lib = true}) + +local none = {} +local partition_defs = { + { + name = "empty_buckets", + groups = none, + items = {"bucket:bucket_empty", "bucket_wooden:bucket_empty"}, + mods = none, + }, + { + name = "caste_nastroje", + groups = none, + items = {"moreblocks:circular_saw", "unifieddyes:airbrush", "bike:painter", + "advtrains:trackworker", "wrench:wrench", "replacer:replacer", + "ch_extras:total_station", "ch_extras:jumptool", "ch_extras:teleporter_unsellable", + "technic:mining_drill", "technic:mining_drill_mk2", "technic:mining_drill_mk3", + "bridger:scaffolding", "ch_core:chisel", + "orienteering:builder_compass_1", "ch_extras:lupa", "ch_extras:periskop", + "binoculars:binoculars"}, + mods = none, + }, + { + name = "kladivo_kovadlina", + groups = none, + items = none, + mods = {"anvil"}, + }, + { + name = "krumpace", + groups = {"pickaxe"}, + items = none, + mods = none, + }, + { + name = "lopaty", + groups = {"shovel"}, + items = none, + mods = none, + }, + { + name = "motyky", + groups = {"hoe"}, + items = none, + mods = none, + }, + { + name = "sekery", + groups = {"axe"}, + items = none, + mods = none, + }, + { + name = "srpy", + groups = {"sickle"}, + items = none, + mods = none, + }, + { + name = "mitrkosa", + groups = none, + items = {"farming:scythe_mithril"}, + mods = none, + }, + { + name = "trojnástroje", + groups = {"multitool"}, + items = none, + mods = none, + }, + { + name = "klice", + groups = none, + items = none, + mods = {"rotate"}, + }, + + { + name = "cestbudky", + groups = {"travelnet"}, + items = none, + mods = none, + }, + + { + name = "drevo", + groups = {"wood"}, + items = none, + mods = none, + exclude_items = { + "moreblocks:wood_tile", + "moreblocks:wood_tile_center", + "moreblocks:wood_tile_offset", + "moreblocks:wood_tile_full", + "pkarcs:acacia_wood_arc", + "pkarcs:acacia_wood_inner_arc", + "pkarcs:acacia_wood_outer_arc", + "pkarcs:acacia_wood_with_arc", + "pkarcs:aspen_wood_arc", + "pkarcs:aspen_wood_inner_arc", + "pkarcs:aspen_wood_outer_arc", + "pkarcs:aspen_wood_with_arc", + "pkarcs:junglewood_arc", + "pkarcs:junglewood_inner_arc", + "pkarcs:junglewood_outer_arc", + "pkarcs:junglewood_with_arc", + "pkarcs:pine_wood_arc", + "pkarcs:pine_wood_inner_arc", + "pkarcs:pine_wood_outer_arc", + "pkarcs:pine_wood_with_arc", + "pkarcs:wood_arc", + "pkarcs:wood_inner_arc", + "pkarcs:wood_outer_arc", + "pkarcs:wood_with_arc", + }, + -- not_in_mods = {"pkarcs"}, + -- not_in_mods = {"cottages", "moreblocks", "pkarcs"}, + }, + { + name = "drevokmeny", + groups = {"tree"}, + items = none, + mods = none, + exclude_items = {"cottages:water_gen", "bamboo:trunk"}, + }, + --[[ + { + name = "barvy", + groups = {"basic_dye"}, + items = none, + mods = none, + }, + { + name = "ploty", + groups = {"fence"}, + items = none, + mods = none, + exclude_items = {"technic:insulator_clip_fencepost"}, + }, ]] + { + name = "mesesloupky", + groups = {"mesepost_light"}, + items = none, + mods = none, + }, + { + name = "jil", + groups = {"bakedclay"}, + items = none, + mods = none, + }, + { + name = "kvetiny", + groups = {"flower"}, + items = none, + mods = none, + }, + { + name = "vlaky", + groups = {"at_wagon"}, + items = none, + mods = none, + }, + { + name = "elektrickestroje", + groups = {"technic_machine"}, + items = none, + mods = none, + exclude_items = {"digtron:power_connector"}, + }, + --[[ { + name = "obleceni", + groups = {"clothing"}, + items = none, + mods = none, + }, + { + name = "pláště", + groups = {"cape"}, + items = none, + mods = none, + }, + { + name = "technic_nn", + groups = {"technic_lv"}, + items = none, + mods = none, + }, + { + name = "technic_sn", + groups = {"technic_mv"}, + items = none, + mods = none, + }, + { + name = "technic_vn", + groups = {"technic_hv"}, + items = none, + mods = none, + }, ]] + { + name = "listy", + groups = {"leaves"}, + items = none, + mods = none, + }, + { + name = "ingoty", + groups = none, + items = {"basic_materials:brass_ingot", "default:bronze_ingot", "default:tin_ingot", "default:copper_ingot", "default:gold_ingot", "default:steel_ingot", + "moreores:mithril_ingot", "moreores:silver_ingot", "technic:chromium_ingot", "technic:cast_iron_ingot", "technic:stainless_steel_ingot", + "technic:lead_ingot", "technic:carbon_steel_ingot", "technic:mixed_metal_ingot", "technic:zinc_ingot", "technic:uranium0_ingot", + "technic:uranium_ingot", "technic:uranium35_ingot", + "aloz:aluminum_ingot"}, + mods = none, + }, + { + name = "loziska", + groups = none, + items = {"default:stone_with_tin", "default:stone_with_diamond", "default:stone_with_mese", "default:stone_with_copper", "default:stone_with_coal", + "default:stone_with_gold", "default:stone_with_iron", "denseores:large_tin_ore", "denseores:large_diamond_ore", "denseores:large_mese_ore", + "denseores:large_copper_ore", "denseores:large_mithril_ore", "denseores:large_silver_ore", "denseores:large_coal_ore", + "denseores:large_gold_ore", "denseores:large_iron_ore", "moreores:mineral_mithril", "moreores:mineral_silver", + "technic:mineral_chromium", "technic:mineral_lead", "technic:mineral_sulfur", "technic:mineral_uranium", "technic:mineral_zinc", + "aloz:stone_with_bauxite"}, + mods = none, + }, + { + name = "sklo", + groups = none, + items = {"building_blocks:woodglass", "building_blocks:smoothglass", "cucina_vegana:mushroomlight_glass", "darkage:glow_glass", + "darkage:glass", "default:obsidian_glass", "default:glass", "moreblocks:clean_glass", "moreblocks:clean_super_glow_glass", + "moreblocks:clean_glow_glass", "moreblocks:iron_glass", "moreblocks:super_glow_glass", "moreblocks:glow_glass", "moreblocks:coal_glass"}, + mods = none, + }, + { + name = "kombinace", + groups = none, + items = none, + mods = {"comboblock"}, + }, + { + name = "clothing_singlecolor", + groups = {"clothing_singlecolor", "cape_singlecolor"}, + items = none, + mods = none, + }, + { + name = "clothing_stripy", + groups = {"clothing_stripy", "cape_stripy"}, + items = none, + mods = none, + }, + { + name = "clothing_squared", + groups = {"clothing_squared", "cape_squared"}, + items = none, + mods = none, + }, + { + name = "clothing_fabric_singlecolor", + groups = {"clothing_fabric_singlecolor"}, + items = none, + mods = none, + }, + { + name = "clothing_fabric_stripy", + groups = {"clothing_fabric_stripy"}, + items = none, + mods = none, + }, + { + name = "clothing_fabric_squared", + groups = {"clothing_fabric_squared"}, + items = none, + mods = none, + }, + --[[ + { + name = "trojdesky", + groups = {"slab"}, + items = none, + mods = none, + }, + { + name = "trojsvahy", + groups = {"slope"}, + items = none, + mods = none, + }, ]] + { + name = "vypocetni_technika", + groups = none, + items = { + "homedecor:alarm_clock", "homedecor:digital_clock", "homedecor:dvd_vcr", + "homedecor:stereo", "homedecor:tv_stand", + }, + mods = {"computers", "digiterms", "home_workshop_machines"}, + }, + { + name = "platforms_1", + groups = {"platform=1"}, + items = none, + mods = none, + }, + { + name = "platforms_2", + groups = {"platform=2"}, + items = none, + mods = none, + }, + { + name = "platforms_3", + groups = {"platform=3"}, + items = none, + mods = none, + }, + { + name = "platforms_4", + groups = {"platform=4"}, + items = none, + mods = none, + }, +} + +function ch_core.overridable.is_clothing(item_name) + return minetest.get_item_group(item_name, "clothing") > 0 or + minetest.get_item_group(item_name, "cape") > 0 +end + +function ch_core.overridable.is_stairsplus_shape(item_name, item_def) + return false +end + +function ch_core.overridable.is_cnc_shape(item_name, item_def) + return false +end + +function ch_core.overridable.is_other_shape(item_name, groups) + return + (groups.fence and item_name ~= "technic:insulator_clip_fencepost") or + groups.gravestone or + groups.streets_manhole or + groups.streets_stormdrain or + item_name:sub(1, 7) == "pkarcs:" or + item_name:sub(1, 8) == "pillars:" or + item_name:sub(1, 10) == "si_frames:" +end + +local function is_experimental(name, groups) + return name:sub(1, 8) == "ch_test:" or (groups.experimental or 0) > 0 +end + +local function is_streets_signs(name, groups) + return name:sub(1, 8) == "streets:" and (groups.streets_tool or groups.sign) +end + +local categories = { + { + description = "výchozí paleta předmětů", + condition = function(itemstring, name, def, groups, palette_index) + local o = ch_core.overridable + return + not o.is_clothing(name) and + not o.is_stairsplus_shape(name, def) and + not o.is_cnc_shape(name, def) and + not o.is_other_shape(name, groups) and + not is_experimental(name, groups) and + not is_streets_signs(name, groups) and + (not groups.dye or groups.basic_dye) and + not groups.platform and + name:sub(1, 16) ~= "clothing:fabric_" and + name:sub(1, 15) ~= "letters:letter_" + end, + icon = { + {image = "ui_category_all.png^[resize:24x24", item = "unified_inventory:bag_large"}, + }, + }, + { + description = "tvary", + condition = function(itemstring, name, def, groups, palette_index) + local o = ch_core.overridable + return o.is_stairsplus_shape(name, def) or + o.is_cnc_shape(name, def) or + o.is_other_shape(name, groups) + end, + icon = { + {image = "[combine:120x120:-4,-4=technic_cnc_bannerstone.png^[resize:20x20", item = "technic:cnc"}, + }, + }, + { + description = "lakované předměty", + condition = function(itemstring, name, def, groups, palette_index) + return (groups.ud_param2_colorable or 0) > 0 and not is_experimental(name, groups) + end, + icon = { + {image = "lrfurn_armchair_inv.png^[resize:24x24", item = "lrfurn:armchair"}, + }, + }, + { + description = "barviva", + condition = function(itemstring, name, def, groups, palette_index) + return groups.dye ~= nil + end, + icon = { + {image = "dye_green.png^[resize:24x24", item = "dye:green"}, + }, + }, + { + description = "dopravní značení", + condition = function(itemstring, name, def, groups, palette_index) + return is_streets_signs(name, groups) or name == "streets:smallpole" or name == "streets:bigpole" or name == "streets:bigpole_short" + end, + icon = { + {image = "streets_sign_eu_50.png^[resize:24x24", item = "streets:sign_eu_50"}, + }, + }, + { + description = "jídlo a pití", + condition = function(itemstring, name, def, groups, palette_index) + return groups.ch_food ~= nil or groups.drink ~= nil or groups.ch_poison ~= nil + end, + icon = { + {image = "ch_extras_parekvrohliku.png^[resize:24x24", item = "ch_extras:parekvrohliku"}, + }, + }, + { + description = "látky (na šaty)", + condition = function(itemstring, name, def, groups, palette_index) + return name:sub(1, 16) == "clothing:fabric_" + end, + icon = { + { + image = "(clothing_fabric.png^[multiply:#f8f7f3)^(((clothing_fabric.png^clothing_inv_second_color.png)^[makealpha:0,0,0)^[multiply:#00b4e8)^[resize:24x24", + item = "clothing:fabric_white", + }, + }, + }, + { + description = "lokomotivy a vagony", + condition = function(itemstring, name, def, groups, palette_index) + return groups.at_wagon ~= nil + end, + icon = { + {image = "moretrains_engine_japan_inv.png^[resize:24x24", item = "advtrains:moretrains_engine_japan"}, + }, + }, + { + description = "nástroje", + condition = function(itemstring, name, def, groups, palette_index) + return minetest.registered_tools[name] ~= nil + end, + icon = { + {image = "moreores_tool_mithrilpick.png^[resize:24x24", item = "moreores:pick_mithril"}, + {image = "default_tool_mesepick.png", item = "default:pick_mese"}, + }, + }, + { + description = "nástupiště", + condition = function(itemstring, name, def, groups, palette_index) + return (groups.platform or 0) > 0 + end, + icon = { + {image = "basic_materials_cement_block.png^[resize:128x128^advtrains_platform.png^[resize:16x16", item = "advtrains:platform_low_cement_block"} + }, + }, + { + description = "oblečení a obuv", + condition = function(itemstring, name, def, groups, palette_index) + return ch_core.overridable.is_clothing(name) + end, + icon = { + {image = "(clothing_inv_shirt.png^[multiply:#98cd61)^[resize:24x24", item = "clothing:shirt_green"}, + }, + }, + { + description = "všechny předměty", + condition = function(itemstring, name, ndef, groups, palette_index) + return true + end, + icon = { + {image = "[combine:40x40:-11,-3=letters_pattern.png\\^letters_star_overlay.png\\^[makealpha\\:255,126,126^[resize:16x16", item = "letters:letter_star"}, + }, + }, + { + description = "experimentální předměty", + condition = function(itemstring, name, ndef, groups, palette_index) + return is_experimental(name, groups) + end, + icon = { + {image = "ch_test_4dir_1.png^[resize:16x16", item = "ch_test:test_color"}, + }, + }, + { + description = "test: svítící bloky", + condition = function(itemstring, name, def, groups, palette_index) + return minetest.registered_nodes[name] ~= nil and def.paramtype == "light" and (def.light_source or 0) > 0 + end, + icon = { + {image = "default_fence_pine_wood.png^default_mese_post_light_side.png^[makealpha:0,0,0^[resize:16x16", item = "default:mese_post_light_pine_wood"}, + }, + }, + { + description = "test: železnice kromě vozidel", + condition = function(itemstring, name, def, groups, palette_index) + return name:match("^advtrains") and not groups.at_wagon + end, + icon = { + {image = "advtrains_dtrack_placer.png^[resize:24x24", item = "advtrains:dtrack_placer"}, + }, + }, +} + +local function get_default_categories() + local descriptions, icons = {}, {} + for i, category_def in ipairs(categories) do + descriptions[i] = category_def.description.." [0]" + icons[i] = "unknown_item.png^[resize:16x16" + end + return { descriptions = descriptions, filter = {}, icons = icons } +end + +local function compute_categories(itemstrings) + local counts = {} + local descriptions = {} + local filter = {} + local icons = {} + local itemstrings_set = {} + local registered_items = minetest.registered_items + local string_cache = {} + + for i = 1, #categories do + counts[i] = 0 + end + + for _, itemstring in ipairs(itemstrings) do + if not itemstrings_set[itemstring] then + itemstrings_set[itemstring] = true + local stack = ItemStack(itemstring) + local name = stack:get_name() + local def = registered_items[name] + if def ~= nil then + local groups = def.groups or none + local palette_index + if name ~= itemstring then + palette_index = stack:get_meta():get_int("palette_index") + end + local mask = "" + for i, category_def in ipairs(categories) do + if category_def.condition(itemstring, name, def, groups, palette_index) then + mask = mask.."1" + counts[i] = counts[i] + 1 + else + mask = mask.."0" + end + end + if string_cache[mask] ~= nil then + mask = string_cache[mask] + else + string_cache[mask] = mask + end + filter[itemstring] = mask + end + end + end + for i, category_def in ipairs(categories) do + descriptions[i] = category_def.description.." ["..counts[i].."]" + icons[i] = "unknown_item.png^[resize:16x16" + for _, icon_def in ipairs(category_def.icon) do + if icon_def.item == nil or minetest.registered_items[icon_def.item] ~= nil then + icons[i] = assert(icon_def.image) + break + end + end + end + return { descriptions = descriptions, filter = filter, icons = icons } +end + +ch_core.creative_inventory = { + categories = get_default_categories(), + --[[ + = { + descriptions[index] = popisek, -- velikost #descriptions udává počet existujících kategorií + filter = { + [itemstring] = "00100[...]", -- maska kategorií pro každý itemstring + }, + icons[index] = textura, -- ikona kategorie (obrázek) + } + ]] + items_by_order = {}, + partitions_by_name = { + others = { + name = "others", + items_by_order = {}, + }, + }, + not_initialized = true, +} + +local function generate_palette_itemstrings(name, paramtype2, limit, list_to_add) + if list_to_add == nil then + list_to_add = {} + end + if limit == nil then + limit = 256 + end + local step + if paramtype2 == "color" then + step = 1 + elseif paramtype2 == "colorfacedir" or paramtype2 == "colordegrotate" then + step = 32 + elseif paramtype2 == "color4dir" then + step = 4 + elseif paramtype2 == "colorwallmounted" then + step = 8 + else + table.insert(list_to_add, name) + return list_to_add + end + local i = 0 + while i < limit and i * step < 256 do + local itemstring = minetest.itemstring_with_palette(name, i * step) + table.insert(list_to_add, itemstring) + i = i + 1 + end + return list_to_add +end + +local function sort_items(itemstrings, group_by_mod) + -- items is expected to be a sequence of item strings, e. g. {"default:cobble", "default:stick", ...} + -- the original list is not changed; the new list is returned + local counter_nil, counter_same, counter_diff = 0, 0, 0 + local itemstring_to_key = {} + + for _, itemstring in ipairs(itemstrings) do + local stack = ItemStack(itemstring) + local name = stack:get_name() + local desc = stack:get_description() or "" + local tdesc = minetest.get_translated_string("cs", desc) + if tdesc == nil then + counter_nil = counter_nil + 1 + tdesc = "" + else + if tdesc == desc then + counter_same = counter_same + 1 + else + counter_diff = counter_diff + 1 + end + end + if group_by_mod then + local index = name:find(":") + if index then + tdesc = name:sub(1, index)..tdesc + end + end + local palette_index = stack:get_meta():get_int("palette_index") + if palette_index > 0 then + tdesc = string.format("%s/%03d", tdesc, palette_index) + end + itemstring_to_key[itemstring] = ch_core.utf8_radici_klic(tdesc, false) + end + + local result = table.copy(itemstrings) + table.sort(result, function(a, b) return itemstring_to_key[a] < itemstring_to_key[b] end) + -- minetest.log("info", "sort_items() stats: "..counter_diff.." differents, "..counter_same.." same, "..counter_nil.." nil, "..(counter_diff + counter_same + counter_nil).." total, count = "..#result..".") + return result +end + +local creative_inventory_initialized = false + +-- should be called when any player logs in +function ch_core.update_creative_inventory(force_update) + if creative_inventory_initialized and not force_update then + minetest.log("verbose", "will not update_creative_inventory(): "..(creative_inventory_initialized and "true" or "false").." "..(force_update and "true" or "false")) + return false + end + minetest.log("verbose", "will update_creative_inventory()") + + -- 1. naplň překladové tabulky + local name_to_partition = {} + local group_to_partition = {} + local mod_to_partition = {} + local partition_to_exclude_items = {others = none} + for _ --[[order]], part_def in ipairs(partition_defs) do + if (part_def.exclude_items or none)[1] then + local set = {} + partition_to_exclude_items[part_def.name] = set + for _, name in ipairs(part_def.exclude_items) do + set[name] = true + end + else + partition_to_exclude_items[part_def.name] = none + end + for _, name in ipairs(part_def.items or none) do + if name_to_partition[name] then + minetest.log("warning", "ERROR in creative_inventory! Item "..name.." has been already set to partition "..name_to_partition[name].." while it is also set to partition "..part_def.name.."!") + else + name_to_partition[name] = part_def.name + end + end + for _, group in ipairs(part_def.groups or none) do + if group_to_partition[group] then + minetest.log("warning", "ERROR in creative_inventory! Group "..group.." has been already set to partition "..group_to_partition[group].." while it is also set to partition "..part_def.name.."!") + else + group_to_partition[group] = part_def.name + end + end + for _, mod in ipairs(part_def.mods or none) do + if mod_to_partition[mod] then + minetest.log("warning", "ERROR in creative_inventory! Mod "..mod.." has been already set to partition "..mod_to_partition[mod].." while it is also set to partition "..part_def.name.."!") + else + mod_to_partition[mod] = part_def.name + end + end + end + + -- 2. projdi registrované předměty a zařaď je do příslušných oddílů + local existing_partitions = {} + + for name, def in pairs(minetest.registered_items) do + local groups = def.groups or none + local nici = groups.not_in_creative_inventory + if (def.description or "") ~= "" and (nici == nil or nici <= 0) then -- not_in_creative_inventory => skip + local partition = "others" + if def._ch_partition then + partition = def._ch_partition + elseif name_to_partition[name] then + partition = name_to_partition[name] + else + local mod --[[, subname]] = name:match("^([^:]*):([^:]*)$") + local success = false + for group, rank in pairs(groups) do + if rank > 0 then + local groupplus = group.."="..rank + if group_to_partition[group] and not partition_to_exclude_items[group_to_partition[group]][name] then + partition = group_to_partition[group] + success = true + break + elseif group_to_partition[groupplus] and not partition_to_exclude_items[group_to_partition[groupplus]][name] then + partition = group_to_partition[groupplus] + success = true + break + end + end + end + if not success then + if mod and mod_to_partition[mod] and not partition_to_exclude_items[mod_to_partition[mod]][name] then + partition = mod_to_partition[mod] + end + end + end + + if partition_to_exclude_items[partition][name] then + partition = "others" + end + + local partition_list = existing_partitions[partition] + if not partition_list then + partition_list = {} + existing_partitions[partition] = partition_list + end + if groups.ui_generate_palette_items ~= nil and groups.ui_generate_palette_items > 0 then + generate_palette_itemstrings(name, def.paramtype2, groups.ui_generate_palette_items, partition_list) + else + table.insert(partition_list, name) + end + end + end + + -- 3. vyjmi oddíl "others" pro samostatné zpracování + local partition_others_list = existing_partitions.others + existing_partitions.others = nil + + -- 4. seřaď předměty v oddílech + for partition_name, item_list in pairs(table.copy(existing_partitions)) do + existing_partitions[partition_name] = sort_items(item_list, false) + end + if partition_others_list ~= nil then + partition_others_list = sort_items(partition_others_list, true) + end + + -- 5. seřaď oddíly + local partitions_in_order = {} + for _, part_def in ipairs(partition_defs) do + local partition_list = existing_partitions[part_def.name] + if partition_list then + table.insert(partitions_in_order, { name = part_def.name, items_by_order = partition_list }) + existing_partitions[part_def.name] = nil + end + end + local remaining_partitions = {} + for part_name, _ in pairs(existing_partitions) do + table.insert(remaining_partitions, part_name) + end + table.sort(remaining_partitions) + for _, part_name in ipairs(remaining_partitions) do + table.insert(partitions_in_order, { name = part_name, items_by_order = existing_partitions[part_name]}) + end + if partition_others_list then + table.insert(partitions_in_order, { name = "others", items_by_order = partition_others_list}) + end + + -- 6. sestav z nich partitions_by_name a items_by_order + local partitions_by_name = {} + local items_by_order = {} + local partitions_by_name_count = 0 + + for _, part_info in pairs(partitions_in_order) do + partitions_by_name[part_info.name] = part_info.items_by_order + table.insert_all(items_by_order, part_info.items_by_order) + partitions_by_name_count = partitions_by_name_count + 1 + end + + -- 7. přidej kategorie + local ci_categories = compute_categories(items_by_order) + + -- commit + local new_ci = { + categories = ci_categories, + items_by_order = items_by_order, + partitions_by_name = partitions_by_name, + } + ch_core.creative_inventory = new_ci + minetest.log("action", "ch_core creative_inventory updated: "..#items_by_order.." items in "..partitions_by_name_count.." partitions") + creative_inventory_initialized = true + return new_ci +end + +local ifthenelse = ch_core.ifthenelse +local function cmp_true_first(a, b) + if a then + return ifthenelse(b, 0, -1) + else + return ifthenelse(b, 1, 0) + end +end +local function cmp_str(a, b) + if a < b then + return -1 + elseif a > b then + return 1 + else + return 0 + end +end +local function cmp_inv(f) + return function(a, b, options) + return -f(a, b, options) + end +end + +local comparisons = { + { + name = "empty_last", + description_asc = "prázdná pole na konec", + description_desc = "prázdná pole první", + cmp = function(a, b) + local count_a, count_b = a:get_count(), b:get_count() + return cmp_true_first(count_a > 0, count_b > 0) + end, + }, + { + name = "by_description", + description_asc = "podle popisku (vzestupně)", + description_desc = "podle popisku (sestupně)", + cmp = function(a, b, options) + local s_a, s_b = a:get_description(), b:get_description() + local lang_code = options.lang_code + if s_a ~= nil then + if lang_code ~= nil then + s_a = minetest.get_translated_string(lang_code, s_a) + end + else + s_a = a:get_name() + end + if s_b ~= nil then + if lang_code ~= nil then + s_b = minetest.get_translated_string(lang_code, s_b) + end + else + s_b = b:get_name() + end + return cmp_str(ch_core.utf8_radici_klic(s_a, true), ch_core.utf8_radici_klic(s_b, true)) + end, + }, + { + name = "by_modname", + description_asc = "podle módu (vzestupně)", + description_desc = "podle módu (sestupně)", + cmp = function(a, b) + local sa = a:get_name():match("^([^:]*):.*") or "" + local sb = b:get_name():match("^([^:]*):.*") or "" + return cmp_str(sa, sb) + end, + }, + { + name = "by_itemname", + description_asc = "podle technického názvu (vzestupně)", + description_desc = "podle technického názvu (sestupně)", + cmp = function(a, b) + local sa = a:get_name():match("^[^:]*:(.*)$") or a:get_name() + local sb = b:get_name():match("^[^:]*:(.*)$") or b:get_name() + return cmp_str(sa, sb) + end, + }, + { + name = "by_count", + description_asc = "podle počtu (od nejmenšího)", + description_desc = "podle počtu (od největšího)", + cmp = function(a, b) + return a:get_count() - b:get_count() + end, + }, + { + name = "tools_first", + description_asc = "nástroje první", + description_desc = "nástroje na konec", + cmp = function(a, b) + return cmp_true_first(minetest.registered_tools[a:get_name()], minetest.registered_tools[b:get_name()]) + end, + }, + { + name = "tools_by_wear", + description_asc = "nástroje podle opotřebení (od nejmenšího)", + description_desc = "nástroje podle opotřebení (od největšího)", + cmp = function(a, b) + if minetest.registered_tools[a:get_name()] and minetest.registered_tools[b:get_name()]then + return a:get_wear() - b:get_wear() + else + return 0 + end + end, + }, + { + name = "books_by_ick", + description_asc = "knihy podle IČK (vzestupně)", + description_desc = "knihy podle IČK (sestupně)", + cmp = function(a, b) + if a:is_empty() or b:is_empty() then + return 0 + end + local a_name, b_name = a:get_name(), b:get_name() + if minetest.get_item_group(a_name, "book") == 0 or minetest.get_item_group(b_name, "book") == 0 then + return 0 + end + local a_meta, b_meta = a:get_meta(), b:get_meta() + local a_ick = ("0000000000000000"..a_meta:get_string("ick")):sub(-16, -1) + local b_ick = ("0000000000000000"..b_meta:get_string("ick")):sub(-16, -1) + return cmp_str(a_ick, b_ick) + end, + }, + { + name = "books_first", + description_asc = "knihy první", + description_desc = "knihy na konec", + cmp = function(a, b) + return cmp_true_first(not a:is_empty() and minetest.get_item_group(a:get_name(), "book") ~= 0, not b:is_empty() and minetest.get_item_group(b:get_name(), "book") ~= 0) + end, + }, + { + name = "books_by_author", + description_asc = "knihy podle autorství (vzestupně)", + description_desc = "knihy podle autorství (sestupně)", + cmp = function(a, b) + if a:is_empty() or minetest.get_item_group(a:get_name(), "book") == 0 or b:is_empty() or minetest.get_item_group(b:get_name(), "book") == 0 then + return 0 + end + return cmp_str(ch_core.utf8_radici_klic(a:get_meta():get_string("author"), false), ch_core.utf8_radici_klic(b:get_meta():get_string("author"), false)) + end, + }, + { + name = "books_by_title", + description_asc = "knihy podle názvu (vzestupně)", + description_desc = "knihy podle názvu (sestupně)", + cmp = function(a, b) + if a:is_empty() or minetest.get_item_group(a:get_name(), "book") == 0 or b:is_empty() or minetest.get_item_group(b:get_name(), "book") == 0 then + return 0 + end + return cmp_str(ch_core.utf8_radici_klic(a:get_meta():get_string("title"), false), ch_core.utf8_radici_klic(b:get_meta():get_string("title"), false)) + end, + }, +} + +local name_to_comparison_index = {} +local choices = {} +for i, cmp_def in ipairs(comparisons) do + name_to_comparison_index[cmp_def.name] = i + if cmp_def.description_asc ~= nil then + table.insert(choices, {name = cmp_def.name, desc = false, description = cmp_def.description_asc}) + end + if cmp_def.description_desc ~= nil then + table.insert(choices, {name = cmp_def.name, desc = true, description = cmp_def.description_desc}) + end +end + +function ch_core.sort_itemstacks(stacks, order_types, lang_code) + local cmps = {} + for _, otype in ipairs(order_types) do + local cmp_index = name_to_comparison_index[otype.name] + if cmp_index == nil then + error("Invalid order type '"..otype.name.."'!") + end + if otype.desc then + table.insert(cmps, cmp_inv(comparisons[cmp_index].cmp)) + else + table.insert(cmps, comparisons[cmp_index].cmp) + end + end + local options = {lang_code = lang_code} + table.sort(stacks, function(a, b) + local result + for i = 1, #cmps do + result = cmps[i](a, b, options) + if result < 0 then + return true + elseif result > 0 then + return false + end + end + return 0 + end) +end + +--[[ +Příklad: + local stacks = inv:get_list("main") + ch_core.sort_itemstacks(stacks, { + {name = "empty_last"}, + {name = "tools_first", desc = true}, + {name = "by_description"}, + {name = "by_modname"}, + {name = "by_itemname"}, + {name = "by_count", desc = true}, + }, ch_data.online_charinfo[player_name].lang_code) +]] + +ch_core.close_submod("creative_inventory") |