diff --git a/.cdb.json b/.cdb.json new file mode 100644 index 0000000..59f319c --- /dev/null +++ b/.cdb.json @@ -0,0 +1,18 @@ +{ + "type": "MOD", + "title": "X Enchanting", + "name": "x_enchanting", + "short_description": "Adds Enchanting Mechanics and API.", + "dev_state": "MAINTENANCE_ONLY", + "tags": [ + "pvp", + "shooter", + "survival", + "tools", + "magic" + ], + "license": "LGPL-2.1-or-later", + "media_license": "CC-BY-SA-4.0", + "repo": "https://bitbucket.org/minetest_gamers/x_enchanting/src/master/", + "issue_tracker": "https://bitbucket.org/minetest_gamers/x_enchanting/issues?status=new&status=open" +} diff --git a/.luarc.json b/.luarc.json new file mode 100644 index 0000000..2e45463 --- /dev/null +++ b/.luarc.json @@ -0,0 +1,88 @@ +{ + "$schema": "https://raw.githubusercontent.com/sumneko/vscode-lua/master/setting/schema.json", + "runtime": { + "version": "Lua 5.1", + "path": [ + "?.lua", + "?/init.lua" + ], + "pathStrict": true + }, + "workspace": { + "maxPreload": 1600, + "preloadFileSize": 1000, + "ignoreDir": [ + "/locale/", + "/libs/", + "/3rd", + "/.vscode", + "/meta", + "/.git", + "/docs", + "/bin" + ], + "checkThirdParty": false + }, + "typeFormat": { + "config": { + "format_line": "false" + } + }, + "type": { + "castNumberToInteger": true + }, + "doc": { + "privateName": [ + "_*" + ] + }, + "diagnostics": { + "disable": [ + "close-non-object" + ], + "groupFileStatus": { + "ambiguity": "Any", + "await": "Any", + "duplicate": "Any", + "global": "Any", + "luadoc": "Any", + "redefined": "Any", + "strict": "Any", + "type-check": "Any", + "unbalanced": "Any", + "unused": "Any" + }, + "ignoredFiles": "Disable", + "libraryFiles": "Disable", + "neededFileStatus": { + "codestyle-check": "Any" + }, + "disableScheme": [ + "git", + "type" + ], + "globals": [ + "DIR_DELIM", + "INIT", + "minetest", + "core", + "dump", + "dump2", + "Raycast", + "Settings", + "PseudoRandom", + "PerlinNoise", + "VoxelManip", + "SecureRandom", + "VoxelArea", + "PerlinNoiseMap", + "PcgRandom", + "ItemStack", + "AreaStore", + "unpack", + "vector", + "default", + "XEnchanting" + ] + } +} diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..b6f27f1 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +engine-strict=true diff --git a/README.md b/README.md index 0135d20..e14da18 100644 --- a/README.md +++ b/README.md @@ -1,73 +1,66 @@ # Enchanting Table and API [x_enchanting] -Adds bow and arrows to Minetest. The goal of this Mod is to make most complete single bow with arrow what will work with MTG damage system, time from last punch as simple as possible. Eventually due to the damage tiers in MTG additional arrows were added. +Adds Enchanting Mechanics and API. -![screenshot](screenshot.1.png) - -Video: https://youtu.be/pItpltmUoa8 +![screenshot](screenshot.png) ## Features -* bow will force you sneak when loaded (optional dep. playerphysics) -* loaded bow will slightly adjust the player FOV -* bow uses minetest tool capabilities - if the bow is not loaded for long enough (time from last puch) the arrow will fly shorter range -* charged bow in inventory will discharge and give back the arrow when not selected -* arrow uses raycast -* arrow has chance of critical shots/hits (only on full punch interval) -* arrow uses minetest damage calculation (including 3d_armor) for making damage (no hardcoded values) -* arrows stick to nodes, players and entitites -* arrows remove them self from the world after some time -* arrows remove them self if there are already too many arrows attached to node, player, entity -* arrow continues to fly downwards when attached node is dug -* arrow flies under water for short period of time and then sinks -* arrows adjusts pitch when flying -* arrows can be picked up again after stuck in solid nodes -* registers only one entity reused for all arrows -* target block reduces fall damage by -30 -* quiver for more arrow storage (can hold only arrows) -* quiver perks when in inventory (faster arrows, more arrow damage...) -* quiver shows temporarily its inventory in HUD overlay when loading or shooting (quickview) -* quiver item shows its content in infotext (hover over the item) -* X Bows API for creating custom shooters and projectiles -* 3d quiver shown in 3rd person view (compatible with 3d armor) +* adds enchanting table +* supports all registered tools with known tool groups: pickaxe, shovel, axe, sword, e.g. `groups = {pickaxe = 1}` +* supports `default:bookshelf` or anything with `group:bookshelf` +* enchanting trade is for `default:mese_crystal` or anything with `groups = {enchanting_trade = 1}` +* adds enchantability for all MT default tools, for custom tools the enchantability can be set in the item group, e.g. `groups = {enchantability = 15}` +* uses only MT engine mechanics (e.g. tool capabilities) +* enchanted items have detailed enchantments description/short description +* mesh node model +* mesh entity model and animations + +NOTE: item inventory/wield image will not be adjusted until this feature is supported by MT engine, see: https://github.com/minetest/minetest/issues/5686 ## How To -### Bow +### Enchanting Setup -With the bow selected in hotbar and in your hand, press right click on mouse (PC) or the same action as when placing blocks, to load the bow. -For bow to be loaded you have to have arrows in the arrow/quiver inventory - there should be extra tab in your inventory MOD to show arrow and quiver inventory slots. -Arrows and quivers in the players main inventory don't count and will not be used. -You have to have arrows and/or quiver in dedicated arrow/quiver inventory slots in order to charge the bow. -Charging bow will have slight sound effect and can be fired at any time with left click (PC) -or the same action as when you are digging a block. Waiting for full charge of the bow is recommended -as it will give the arrow full speed (maximum shooting distance) and chance for critical arrow (double damage). +For maximum level of enchantments you need maximum of 15 bookshelfs around the enchanting table, maximum of 2 blocks away. Maximum level is 30. -There are few indications on how to know when the bow is fully charged: +### Enchanting Table -* there is a distinct "click" sound -* each arrow has "charge time" in the description -* after shooting, arrow will have particle trail +To be able to enchant items you need a trade item (by default `default:mese_crystal` or anything with `groups = {enchanting_trade = 1}`). Higher level enchantments costs more: level 1,2,3 costs mese crystals 1,2,3. +When place item in the enchantment table item slot you can see three buttons with: + - left side the trade cost amount + - middle the enchantment you will get + maybe more enchantments + - right side the base level for the enchantment (depends on how many bookshelfs are in reach) +When you place item in the enchantment table trade slot you will see that some buttons are now enabled and can be clicked on - depends on trade amount available. +The enchantments shown in the enchantment table will be always the same for item - this will change after you enchant an item. After enchanting an item a new enchantments will be shown. -There are few indications on how to know when the arrow is a critical arrow: +### Item Enchantability -* there is a distinct arrow flying sound -* after shooting, arrow will have red particle trail +All default tools have enchantability set. Higher enchantability = higher chance of getting better enchantments. +Items enchantibility from worst to best: + - stone + - diamond + - steel + - wood / mese + - bronze -If you shoot the arrow before the bow is fully charged the speed/distance will be lower and no arrow particle trail will be shown (also no chance for critical arrow). -Changing the selection in hotbar will unload the bow and give you back arrow from the unloaded bow - this applies also when login in to the game (bow will be discharged and arrow will be returned to inventory) and also when you drop the charged arrow (discharged bow will be dropped with arrow item). -If you have `playerphysics` or `player_monoids` mod installed, charged bow will slow you down until you release the arrow. +### Every Enchantment Explained -### Quiver +#### Sharpness -Quiver item can hold inventory of arrows. When player has quiver in his/hers quiver inventory slot - there should be extra tab in your inventory MOD to show arrow and quiver inventory slots, bow can take arrows from quiver, otherwise arrows outside of the quiver are used to load the bow. -Though, if arrows from quiver are used to load the bow, the arrows have additional speed and damage. -If we are loading/shooting arrows from quiver, there is temporary quickview HUD overlay shown, peeking in to the quivers inventory from which the arrow was taken. Arrows used from quiver will be faster only when the bow is fully charged - see "How To - Bow" for more information on how to know when bow is fully charged. +Increases melee damage. -There are few indications on how to know when the bow shot arrow from quiver: +#### Fortune -* there is temporary HUD overview shown peeking in to the quiver inventory -* after shooting, arrow will have blue/purple particle trail (if bow was fully charged) +Increases the number and/or chances of specific item drops. This value is not used in the engine; it is the responsibility of the game/mod code to implement this. + +#### Unbreaking + +Increases the item's durability. + +#### Efficiency + +Increases the player's mining speed. Also adds mining groupcaps to item, e.g. enchanted wood pickaxe can mine level 1 nodes (e.g. obsidian) after enchantment. ## Dependencies @@ -75,21 +68,7 @@ There are few indications on how to know when the bow shot arrow from quiver: ## Optional Dependencies -- default (recipes) -- farming (bow and target recipes) -- 3d_armor (calculates damage including the armor) -- mesecons (target can be used to trigger mesecon signal) -- playerphysics (force sneak when holding charged bow) -- player_monoids (force sneak when holding charged bow) -- wool (quiver recipe) -- i3 -- unified_inventory -- simple_skins -- u_skins -- wardrobe -- sfinv -- skinsdb -- player_api (shows 3d quiver) +- xdecor (adjusts conflicting recipe) ## License: @@ -101,106 +80,75 @@ GNU Lesser General Public License v2.1 or later (see included LICENSE file) **CC BY-SA 4.0, Pixel Perfection by XSSheep**, https://minecraft.curseforge.com/projects/pixel-perfection-freshly-updated -- x_bows_bow_wood.png -- x_bows_bow_wood_charged.png -- x_bows_arrow_wood.png -- x_bows_arrow_particle.png -- x_bows_bubble.png -- x_bows_target.png - -Modified by SaKeL: - -- x_bows_arrow_stone.png -- x_bows_arrow_bronze.png -- x_bows_arrow_steel.png -- x_bows_arrow_mese.png -- x_bows_arrow_diamond.png - -**CC-BY-SA-3.0, by paramat** - -- x_bows_hotbar_selected.png -- x_bows_quiver_hotbar.png -- x_bows_single_hotbar.png +- x_enchanting_symbol_1.png +- x_enchanting_symbol_2.png +- x_enchanting_symbol_3.png +- x_enchanting_symbol_4.png +- x_enchanting_symbol_5.png +- x_enchanting_symbol_6.png +- x_enchanting_symbol_7.png +- x_enchanting_symbol_8.png +- x_enchanting_symbol_9.png +- x_enchanting_symbol_10.png +- x_enchanting_symbol_11.png +- x_enchanting_symbol_12.png +- x_enchanting_symbol_13.png +- x_enchanting_symbol_14.png +- x_enchanting_symbol_15.png +- x_enchanting_symbol_16.png +- x_enchanting_symbol_17.png +- x_enchanting_symbol_18.png +- x_enchanting_symbol_19.png +- x_enchanting_symbol_20.png +- x_enchanting_symbol_21.png +- x_enchanting_symbol_22.png +- x_enchanting_symbol_23.png +- x_enchanting_symbol_24.png +- x_enchanting_symbol_25.png +- x_enchanting_symbol_26.png **LGPL-2.1-or-later, by SaKeL** -- x_bows_quiver.png -- x_bows_quiver_open.png -- x_bows_arrow_slot.png -- x_bows_arrow_mesh.png -- x_bows_quiver_mesh.png -- x_bows_quiver_empty_mesh.png -- x_bows_quiver_blank_mesh.png -- x_bows_quiver_slot.png -- x_bows_dmg_0.png -- x_bows_dmg_1.png -- x_bows_dmg_2.png -- x_bows_dmg_3.png -- x_bows_dmg_4.png -- x_bows_dmg_5.png -- x_bows_dmg_6.png -- x_bows_dmg_7.png -- x_bows_dmg_8.png -- x_bows_dmg_9.png - -### Sounds - -**Creative Commons License, EminYILDIRIM**, https://freesound.org - -- x_bows_bow_load.1.ogg -- x_bows_bow_load.2.ogg -- x_bows_bow_load.3.ogg - -**Creative Commons License, bay_area_bob**, https://freesound.org - -- x_bows_bow_loaded.ogg - -**Creative Commons License**, https://freesound.org - -- x_bows_bow_shoot_crit.ogg - -**Creative Commons License, robinhood76**, https://freesound.org - -- x_bows_arrow_hit.1.ogg -- x_bows_arrow_hit.2.ogg -- x_bows_arrow_hit.3.ogg - -**Creative Commons License, brendan89**, https://freesound.org - -- x_bows_bow_shoot.1.ogg - -**Creative Commons License, natty23**, https://freesound.org - -- x_bows_arrow_successful_hit.ogg - -**Creative Commons License, Shamewap**, https://freesound.org - -- x_bows_quiver.1.ogg -- x_bows_quiver.2.ogg -- x_bows_quiver.3.ogg -- x_bows_quiver.4.ogg -- x_bows_quiver.5.ogg -- x_bows_quiver.6.ogg -- x_bows_quiver.7.ogg -- x_bows_quiver.8.ogg -- x_bows_quiver.9.ogg +- x_enchanting_image_button_disabled.png +- x_enchanting_image_button.png +- x_enchanting_image_trade_1.png -- Derived from a texture by VanessaE (CC BY-SA 3.0) +- x_enchanting_image_trade_2.png -- Derived from a texture by VanessaE (CC BY-SA 3.0) +- x_enchanting_image_trade_3.png -- Derived from a texture by VanessaE (CC BY-SA 3.0) +- x_enchanting_scroll_handles_mesh.png -- Derived from a textures by paramat (CC BY-SA 3.0) and TumeniNodes (CC BY-SA 3.0) +- x_enchanting_scroll_mesh.png -- Derived from a texture TumeniNodes (CC BY-SA 3.0) +- x_enchanting_scroll_particle.png +- x_enchanting_table.png +- x_enchanting_trade_slot.png ### Models **LGPL-2.1-or-later, by SaKeL** -- x_bows_arrow.obj -- x_bows_arrow.blend +- x_enchanting_scroll.b3d +- x_enchanting_table.obj -**Original model by MirceaKitsune (CC BY-SA 3.0).** -**Various alterations and fixes by kilbith, sofar, xunto, Rogier-5, TeTpaAka, Desour, stujones11, An0n3m0us (CC BY-SA 3.0):** +### Sounds -Modified by SaKeL (added quiver): +**Mixkit Sound Effects Free License**, Sound effects obtained from https://mixkit.co -- x_bows_3d_armor_character.b3d -- x_bows_3d_armor_character.blend -- x_bows_character.b3d -- x_bows_character.blend +x_enchanting_enchant.ogg + +**Standard License**, Sound effects obtained from https://mixkit.co + +x_enchanting_scroll.1.ogg +x_enchanting_scroll.2.ogg +x_enchanting_scroll.3.ogg +x_enchanting_scroll.4.ogg +x_enchanting_scroll.5.ogg +x_enchanting_scroll.6.ogg +x_enchanting_scroll.7.ogg +x_enchanting_scroll.8.ogg +x_enchanting_scroll.9.ogg +x_enchanting_scroll.10.ogg +x_enchanting_scroll.11.ogg +x_enchanting_scroll.12.ogg +x_enchanting_scroll.13.ogg +x_enchanting_scroll.14.ogg ## Installation diff --git a/api.lua b/api.lua index e8e3cd4..b4c6252 100644 --- a/api.lua +++ b/api.lua @@ -1,5 +1,7 @@ +default = minetest.global_exists('default') and default --[[@as MtgDefault]] + +---@type XEnchanting XEnchanting = { - -- add enchantability to default tools tools_enchantability = { -- picks ['default:pick_wood'] = 15, @@ -119,6 +121,14 @@ XEnchanting = { }, weight = 10 } + }, + randomseed = os.time(), + form_context = {}, + scroll_animations = { + scroll_open = { { x = 1, y = 40 }, 80, 0, false }, + scroll_close = { { x = 45, y = 84 }, 80, 0, false }, + scroll_open_idle = { { x = 41, y = 42 }, 0, 0, false }, + scroll_closed_idle = { { x = 43, y = 44 }, 0, 0, false } } } @@ -163,28 +173,51 @@ function XEnchanting.get_enchanted_tool_capabilities(self, tool_def, enchantment local tool_stack = ItemStack({ name = tool_def.name }) local tool_capabilities = tool_stack:get_tool_capabilities() local enchantments_desc = {} - - -- print('tool_capabilities #1', dump(tool_capabilities)) + local enchantments_desc_masked = {} for i, enchantment in ipairs(enchantments) do -- Efficiency if enchantment.id == 'efficiency' then + -- apply enchantment if tool_capabilities.groupcaps then -- groupcaps for group_name, def in pairs(tool_capabilities.groupcaps) do + local highest_cap_level = 0 + -- times if def.times then local old_times = def.times local new_times = {} - for lvl, old_time in ipairs(old_times) do + for lvl, old_time in pairs(old_times) do local new_time = old_time - (old_time * (enchantment.value / 100)) if new_time < 0.15 then new_time = 0.15 end - table.insert(new_times, lvl, new_time) + if highest_cap_level < lvl then + highest_cap_level = lvl + end + + new_times[lvl] = new_time + end + + -- extend groupcaps levels + while highest_cap_level > 1 do + highest_cap_level = highest_cap_level - 1 + + if not new_times[highest_cap_level] then + -- add new cap level time + local old_time = new_times[highest_cap_level + 1] + local new_time = old_time * 2 + + if new_time < 0.15 then + new_time = 0.15 + end + + new_times[highest_cap_level] = new_time + end end tool_capabilities.groupcaps[group_name].times = new_times @@ -213,6 +246,12 @@ function XEnchanting.get_enchanted_tool_capabilities(self, tool_def, enchantment enchantments_desc[#enchantments_desc + 1] = self.enchantment_defs[enchantment.id].name .. ' ' .. self.roman_numbers[enchantment.level] + + if #enchantments_desc_masked == 0 then + enchantments_desc_masked[#enchantments_desc_masked + 1] = self.enchantment_defs[enchantment.id].name + .. ' ' + .. self.roman_numbers[enchantment.level] + end end end @@ -243,6 +282,12 @@ function XEnchanting.get_enchanted_tool_capabilities(self, tool_def, enchantment enchantments_desc[#enchantments_desc + 1] = self.enchantment_defs[enchantment.id].name .. ' ' .. self.roman_numbers[enchantment.level] + + if #enchantments_desc_masked == 0 then + enchantments_desc_masked[#enchantments_desc_masked + 1] = self.enchantment_defs[enchantment.id].name + .. ' ' + .. self.roman_numbers[enchantment.level] + end end end @@ -258,6 +303,12 @@ function XEnchanting.get_enchanted_tool_capabilities(self, tool_def, enchantment enchantments_desc[#enchantments_desc + 1] = self.enchantment_defs[enchantment.id].name .. ' ' .. self.roman_numbers[enchantment.level] + + if #enchantments_desc_masked == 0 then + enchantments_desc_masked[#enchantments_desc_masked + 1] = self.enchantment_defs[enchantment.id].name + .. ' ' + .. self.roman_numbers[enchantment.level] + end end -- Fortune @@ -270,29 +321,65 @@ function XEnchanting.get_enchanted_tool_capabilities(self, tool_def, enchantment enchantments_desc[#enchantments_desc + 1] = self.enchantment_defs[enchantment.id].name .. ' ' .. self.roman_numbers[enchantment.level] + + if #enchantments_desc_masked == 0 then + enchantments_desc_masked[#enchantments_desc_masked + 1] = self.enchantment_defs[enchantment.id].name + .. ' ' + .. self.roman_numbers[enchantment.level] + end end end - enchantments_desc = minetest.colorize('#C70039', '\nEnchanted\n') .. table.concat(enchantments_desc, '\n') + enchantments_desc = '\n' .. minetest.colorize('#AE81FF', 'Enchanted') + .. '\n' .. table.concat(enchantments_desc, '\n') + enchantments_desc_masked = table.concat(enchantments_desc_masked, '') .. '...?' - -- print('tool_capabilities #2', dump(tool_capabilities)) - -- print('enchantments_desc', enchantments_desc) - -- return { - -- tool_capabilities = tool_capabilities, - -- enchantments_desc = enchantments_desc - -- } + return { + tool_capabilities = tool_capabilities, + enchantments_desc = enchantments_desc, + enchantments_desc_masked = enchantments_desc_masked + } end -function XEnchanting.set_enchanted_tool_capabilities(self, itemstack, capabilities, description) - -- local tool_def = minetest.registered_tools[itemstack:get_name()] - -- minetest.override_item(tool_def.name, { - -- groups = mergeTables(tool_def.groups, { enchantability = 0 }), - -- tool_capabilities = tool_capabilities - -- }) +function XEnchanting.set_enchanted_tool(self, pos, itemstack, capabilities, description, level, player_name) + local inv = minetest.get_meta(pos):get_inventory() + local tool_def = minetest.registered_tools[itemstack:get_name()] + + if not tool_def then + return + end + + local stack_meta = itemstack:get_meta() + + stack_meta:set_tool_capabilities(capabilities) + stack_meta:set_string('description', itemstack:get_description() .. '\n' .. description) + stack_meta:set_string('short_description', 'Enchanted ' .. itemstack:get_short_description()) + stack_meta:set_int('is_enchanted', 1) + + inv:set_stack('item', 1, itemstack) + + local trade_stack = inv:get_stack('trade', 1) + trade_stack:take_item(level) + inv:set_stack('trade', 1, trade_stack) + + -- set new seed + self.randomseed = tonumber(tostring(os.time()):reverse():sub(1, 9)) --[[@as number]] + + local formspec = self:get_formspec(pos, player_name) + minetest.show_formspec(player_name, 'x_enchanting:table', formspec) + + minetest.sound_play('x_enchanting_enchant', { + gain = 0.3, + pos = pos, + max_hear_distance = 10 + }, true) end -function XEnchanting.get_base_enchantment_level(self, nr_of_bookshelfs, tool_def) +function XEnchanting.get_enchantment_data(self, nr_of_bookshelfs, tool_def) local _nr_of_bookshelfs = nr_of_bookshelfs + local data = { + slots = {} + } if _nr_of_bookshelfs > 15 then _nr_of_bookshelfs = 15 @@ -303,108 +390,187 @@ function XEnchanting.get_base_enchantment_level(self, nr_of_bookshelfs, tool_def ---- -- Base enchantment + math.randomseed(self.randomseed) local base = math.random(1, 8) + math.floor(_nr_of_bookshelfs / 2) + math.random(0, _nr_of_bookshelfs) local top_slot_base_level = math.floor(math.max(base / 3, 1)) local middle_slot_base_level = math.floor((base * 2) / 3 + 1) local bottom_slot_base_level = math.floor(math.max(base, _nr_of_bookshelfs * 2)) - -- print('top_slot_base_level', top_slot_base_level) - -- print('middle_slot_base_level', middle_slot_base_level) - -- print('bottom_slot_base_level', bottom_slot_base_level) + for i, slot_lvl in ipairs({ top_slot_base_level, middle_slot_base_level, bottom_slot_base_level }) do + ---- + -- 1 Applying modifiers to the enchantment level + ---- - ---- - -- 1 Applying modifiers to the enchantment level - ---- + local chosen_enchantment_level = slot_lvl + -- Applying modifiers to the enchantment level + local enchantability = minetest.get_item_group(tool_def.name, 'enchantability') + -- Generate a random number between 1 and 1+(enchantability/2), with a triangular distribution + math.randomseed(self.randomseed) + local rand_enchantability = 1 + math.random(enchantability / 4 + 1) + math.random(enchantability / 4 + 1) + -- Choose the enchantment level + local k = chosen_enchantment_level + rand_enchantability + -- A random bonus, between .85 and 1.15 + math.randomseed(self.randomseed) + local rand_bonus_percent = 1 + ((math.random(0, 99) / 100) + (math.random(0, 99) / 100) - 1) * 0.15 + -- Finally, we calculate the level + local final_level = math.round(k * rand_bonus_percent) - -- Just for testing, this has to come from formspec - local chosen_enchantment_level = 30 - -- Applying modifiers to the enchantment level - local enchantability = minetest.get_item_group(tool_def.name, 'enchantability') - -- Generate a random number between 1 and 1+(enchantability/2), with a triangular distribution - -- print('-------------------') - -- print('enchantability', enchantability) - local rand_enchantability = 1 + math.random(enchantability / 4 + 1) + math.random(enchantability / 4 + 1) - -- print('rand_enchantability', rand_enchantability) - -- Choose the enchantment level - local k = chosen_enchantment_level + rand_enchantability - -- print('k', k) - -- A random bonus, between .85 and 1.15 - local rand_bonus_percent = 1 + ((math.random(0, 99) / 100) + (math.random(0, 99) / 100) - 1) * 0.15 - -- print('rand_bonus_percent', rand_bonus_percent) - -- Finally, we calculate the level - local final_level = math.round(k * rand_bonus_percent) + if final_level < 1 then + final_level = 1 + end - if final_level < 1 then - final_level = 1 - end + ---- + -- 2 Find possible enchantments + ---- - -- print('final_level', final_level) + ---@type {["id"]: string, ["value"]: number | table, ["level"]: number}[] + local possible_enchantments = {} - ---- - -- 2 Find possible enchantments - ---- - local possible_enchantments = {} + -- Get level + -- If the modified level is within two overlapping ranges for the same + -- enchantment type, the higher power value is used. + for enchantment_name, enchantment_def in pairs(self.enchantment_defs) do + local levels = {} - -- Get level - -- If the modified level is within two overlapping ranges for the same - -- enchantment type, the higher power value is used. - for enchantment_name, enchantment_def in pairs(self.enchantment_defs) do - local levels = {} + for level, final_level_range in ipairs(enchantment_def.final_level_range) do + local min = final_level_range[1] + local max = final_level_range[2] - for level, final_level_range in ipairs(enchantment_def.final_level_range) do - local min = final_level_range[1] - local max = final_level_range[2] + if final_level >= min and final_level <= max then + table.insert(levels, level) + end + end - if final_level >= min and final_level <= max then - table.insert(levels, level) + local level = levels[#levels] + + if level then + table.insert(possible_enchantments, { + id = enchantment_name, + value = enchantment_def.level_def[level], + level = level + }) end end - local level = levels[#levels] + ---- + -- 3 Select a set of enchantments from the list + ---- - -- print('levels', enchantment_name, dump(levels)) - -- print('level', enchantment_name, level) + ---@type {["id"]: string, ["value"]: number | table, ["level"]: number}[] + local final_enchantments = {} + local total_weight = 0 - table.insert(possible_enchantments, { - id = enchantment_name, - value = enchantment_def.level_def[level], - level = level + -- calculate total weight + for j, enchantment in ipairs(possible_enchantments) do + total_weight = total_weight + self.enchantment_defs[enchantment.id].weight + end + + math.randomseed(self.randomseed) + local rand_weight = math.random(0, total_weight / 2) + + -- select final enchantments + for j = 1, #possible_enchantments, 1 do + math.randomseed(self.randomseed) + local rand_ench_idx = math.random(1, #possible_enchantments) + local rand_ench = possible_enchantments[rand_ench_idx] + + table.remove(possible_enchantments, rand_ench_idx) + rand_weight = rand_weight - self.enchantment_defs[rand_ench.id].weight + table.insert(final_enchantments, rand_ench) + + -- If `rand_weight` is now negative, select the current enchantment and stop. + if rand_weight < 0 then + break + end + end + + local tool_cap_data = self:get_enchanted_tool_capabilities(tool_def, final_enchantments) + + table.insert(data.slots, i, { + level = slot_lvl, + final_enchantments = final_enchantments, + tool_cap_data = tool_cap_data }) end - -- print('possible_enchantments', dump(possible_enchantments)) - - ---- - -- 3 Select a set of enchantments from the list - ---- - local final_enchantments = {} - local total_weight = 0 - - -- calculate total weight - for i, enchantment in ipairs(possible_enchantments) do - total_weight = total_weight + self.enchantment_defs[enchantment.id].weight - end - - local rand_weight = math.random(0, total_weight / 2) - - -- print('total_weight', total_weight) - -- print('rand_weight', rand_weight) - - -- select final enchantments - for i = 1, #possible_enchantments, 1 do - local rand_ench_idx = math.random(1, #possible_enchantments) - local rand_ench = possible_enchantments[rand_ench_idx] - - table.remove(possible_enchantments, rand_ench_idx) - rand_weight = rand_weight - self.enchantment_defs[rand_ench.id].weight - table.insert(final_enchantments, rand_ench) - - if rand_weight < 0 then - break - end - end - - -- print('final_enchantments', dump(final_enchantments)) - - self:get_enchanted_tool_capabilities(tool_def, final_enchantments) + return data +end + +---Build form +---@param pos Vector +---@param player_name string +---@param data? table +---@return string +function XEnchanting.get_formspec(self, pos, player_name, data) + local spos = pos.x .. ',' .. pos.y .. ',' .. pos.z + local inv = minetest.get_meta(pos):get_inventory() + ---@diagnostic disable-next-line: codestyle-check + local model_scroll_open = 'model[0,0;2,3;x_enchanting_table;x_enchanting_scroll.b3d;x_enchanting_scroll_mesh.png,x_enchanting_scroll_handles_mesh.png,x_enchanting_scroll_mesh.png;89,0;false;false;' .. self.scroll_animations.scroll_open_idle[1].x .. ',' .. self.scroll_animations.scroll_open_idle[1].y .. ';0]' + ---@diagnostic disable-next-line: codestyle-check + local model_scroll_closed = 'model[0,0;2,3;x_enchanting_table;x_enchanting_scroll.b3d;x_enchanting_scroll_mesh.png,x_enchanting_scroll_handles_mesh.png,x_enchanting_scroll_mesh.png;89,0;false;false;' .. self.scroll_animations.scroll_closed_idle[1].x .. ',' .. self.scroll_animations.scroll_closed_idle[1].y .. ';0]' + local model_scroll_is_open + + local formspec = { + 'size[8,9]', + 'label[0, 0;Enchant]', + 'list[nodemeta:' .. spos .. ';item;0, 2.5;1, 1;]', + 'image[1,2.5;1,1;x_enchanting_trade_slot.png;]', + 'list[nodemeta:' .. spos .. ';trade;1, 2.5;1, 1;]', + 'list[current_player;main;0, 4.85;8, 1;]', + 'list[current_player;main;0, 6.08;8, 3;8]', + 'listring[nodemeta:' .. spos .. ';trade]', + 'listring[current_player;main]', + 'listring[nodemeta:' .. spos .. ';item]', + 'listring[current_player;main]' + } + + if default then + formspec[#formspec + 1] = default.get_hotbar_bg(0, 4.85) + end + + -- data + if data then + for i, slot in ipairs(data.slots) do + if #slot.final_enchantments > 0 then + -- show buttons with content + + if inv:get_stack('trade', 1):get_count() >= i then + ---@diagnostic disable-next-line: codestyle-check + formspec[#formspec + 1] = 'image_button[2.5,' .. -0.5 + i .. ';5,1;x_enchanting_image_button.png;slot_' .. i .. ';' .. slot.tool_cap_data.enchantments_desc_masked .. ' ' .. minetest.colorize('#FFFF00', 'level: ' .. slot.level) .. ']' + else + ---@diagnostic disable-next-line: codestyle-check + formspec[#formspec + 1] = 'image_button[2.5,' .. -0.5 + i .. ';5,1;x_enchanting_image_button_disabled.png;slot_' .. i .. ';' .. slot.tool_cap_data.enchantments_desc_masked .. ' ' .. minetest.colorize('#FFFF00', 'level: ' .. slot.level) .. ']' + end + + formspec[#formspec + 1] = 'image[2.5,' .. -0.5 + i .. ';1,1;x_enchanting_image_trade_' .. i .. '.png;]' + else + -- disabled buttons + ---@diagnostic disable-next-line: codestyle-check + formspec[#formspec + 1] = 'image_button[2.5,' .. -0.5 + i .. ';5,1;x_enchanting_image_button_disabled.png;slot_' .. i .. ';]' + end + end + + model_scroll_is_open = true + else + for i = 1, 3, 1 do + -- disabled buttons + ---@diagnostic disable-next-line: codestyle-check + formspec[#formspec + 1] = 'image_button[2.5,' .. -0.5 + i .. ';5,1;x_enchanting_image_button_disabled.png;slot_' .. i .. ';]' + end + + model_scroll_is_open = false + end + + if model_scroll_is_open then + formspec[#formspec + 1] = model_scroll_open + else + formspec[#formspec + 1] = model_scroll_closed + end + + self.form_context[player_name] = { + data = data, + pos = pos + } + + return table.concat(formspec, '') end diff --git a/assets/x_enchanting_image_button.xcf b/assets/x_enchanting_image_button.xcf new file mode 100644 index 0000000..a328646 Binary files /dev/null and b/assets/x_enchanting_image_button.xcf differ diff --git a/assets/x_enchanting_image_trade.xcf b/assets/x_enchanting_image_trade.xcf new file mode 100644 index 0000000..e86f2ef Binary files /dev/null and b/assets/x_enchanting_image_trade.xcf differ diff --git a/assets/x_enchanting_scroll.blend b/assets/x_enchanting_scroll.blend new file mode 100644 index 0000000..f375dd4 Binary files /dev/null and b/assets/x_enchanting_scroll.blend differ diff --git a/assets/x_enchanting_symbols.xcf b/assets/x_enchanting_symbols.xcf new file mode 100644 index 0000000..b4a3167 Binary files /dev/null and b/assets/x_enchanting_symbols.xcf differ diff --git a/bin/lua-language-server-3.5.6-linux-x64.tar.gz b/bin/lua-language-server-3.5.6-linux-x64.tar.gz new file mode 100644 index 0000000..9b23cf5 Binary files /dev/null and b/bin/lua-language-server-3.5.6-linux-x64.tar.gz differ diff --git a/bitbucket-pipelines.yml b/bitbucket-pipelines.yml new file mode 100644 index 0000000..b2b9b18 --- /dev/null +++ b/bitbucket-pipelines.yml @@ -0,0 +1,107 @@ +image: atlassian/default-image:3 + +pipelines: + pull-requests: + "**": + - step: + name: Install Node Dependencies + caches: + - node-modules + - npm + - nvm + script: + - nvm install v17.2.0 + - npm i -g npm@8 + - npm ci + - parallel: + - step: + name: Lua Check + script: + - apt-get update + - apt-get -y install lua5.1 + - apt-get -y install luarocks + - luarocks install luacheck + - luacheck . + - step: + name: Lua Diagnostics + caches: + - node-modules + - npm + - nvm + script: + - nvm use v17.2.0 + - npm run lua-diagnostics + branches: + master: + - step: + name: Install Node Dependencies + caches: + - node-modules + - npm + - nvm + script: + - nvm install v17.2.0 + - npm i -g npm@8 + - npm ci + - parallel: + - step: + name: Lua Check + script: + - apt-get update + - apt-get -y install lua5.1 + - apt-get -y install luarocks + - luarocks install luacheck + - luacheck . + - step: + name: Lua Diagnostics + caches: + - node-modules + - npm + - nvm + script: + - nvm use v17.2.0 + - npm run lua-diagnostics + tags: + "*": + - step: + name: Install Node Dependencies + caches: + - node-modules + - npm + - nvm + script: + - nvm install v17.2.0 + - npm i -g npm@8 + - npm ci + - parallel: + - step: + name: Lua Check + script: + - apt-get update + - apt-get -y install lua5.1 + - apt-get -y install luarocks + - luarocks install luacheck + - luacheck . + - step: + name: Lua Diagnostics + caches: + - node-modules + - npm + - nvm + script: + - nvm use v17.2.0 + - npm run lua-diagnostics + - step: + name: Deploy to ContentDB + caches: + - node-modules + - npm + - nvm + script: + - nvm use v17.2.0 + - npm run push:ci -- --token=$CONTENT_DB_X_ENCHATING_TOKEN --title=$BITBUCKET_TAG +definitions: + caches: + node-modules: ./node_modules + npm: ~/.npm + nvm: ~/.nvm diff --git a/init.lua b/init.lua index bd72326..72493d0 100644 --- a/init.lua +++ b/init.lua @@ -11,12 +11,18 @@ minetest.register_on_mods_loaded(function() for name, tool_def in pairs(minetest.registered_tools) do if XEnchanting:has_tool_group(name) then XEnchanting:set_tool_enchantability(tool_def) - -- print(name, dump(minetest.registered_tools[name]._x_enchanting)) - -- print(name, dump(minetest.registered_tools[name].groups)) end end end) +minetest.register_on_joinplayer(function(player, last_login) + XEnchanting.form_context[player:get_player_name()] = nil +end) + +minetest.register_on_leaveplayer(function(player, timed_out) + XEnchanting.form_context[player:get_player_name()] = nil +end) + local mod_end_time = (minetest.get_us_time() - mod_start_time) / 1000000 print('[Mod] x_enchanting loaded.. [' .. mod_end_time .. 's]') diff --git a/mod.conf b/mod.conf index 3bcdd07..24bb8a3 100644 --- a/mod.conf +++ b/mod.conf @@ -1,6 +1,6 @@ name = x_enchanting -description = Adds Enchanting Table and API. +description = Adds Enchanting Mechanics and API. depends = -optional_depends = +optional_depends = xdecor supported_games = minetest_game min_minetest_version = 5.4 diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..45a8fac --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1388 @@ +{ + "name": "x_enchanting", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "x_enchanting", + "version": "1.0.0", + "license": "LGPL-2.1-or-later", + "devDependencies": { + "jaguar": "^6.0.1", + "node-fetch": "^3.2.10", + "yargs": "^17.6.1" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=8.0.0" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bl/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/browserify-zlib": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.1.4.tgz", + "integrity": "sha512-19OEpq7vWgsH6WkvkBJQDFvJS1uPcbFOQ4v9CU839dO+ZZXUZO6XpE6hNCqvlIIj+4fZvRiJ6DsAQ382GwiyTQ==", + "dev": true, + "dependencies": { + "pako": "~0.2.0" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz", + "integrity": "sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA==", + "dev": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, + "node_modules/findit2": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/findit2/-/findit2-2.2.3.tgz", + "integrity": "sha512-lg/Moejf4qXovVutL0Lz4IsaPoNYMuxt4PA0nGqFxnJ1CTTGGlEO2wKgoDpwknhvZ8k4Q2F+eesgkLbG2Mxfog==", + "dev": true, + "engines": { + "node": ">=0.8.22" + } + }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "dev": true, + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/gunzip-maybe": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/gunzip-maybe/-/gunzip-maybe-1.4.2.tgz", + "integrity": "sha512-4haO1M4mLO91PW57BMsDFf75UmwoRX0GkdD+Faw+Lr+r/OZrOCS0pIBwOL1xCKQqnQzbNFGgK2V2CpBUPeFNTw==", + "dev": true, + "dependencies": { + "browserify-zlib": "^0.1.4", + "is-deflate": "^1.0.0", + "is-gzip": "^1.0.0", + "peek-stream": "^1.1.0", + "pumpify": "^1.3.3", + "through2": "^2.0.3" + }, + "bin": { + "gunzip-maybe": "bin.js" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/is-deflate": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-deflate/-/is-deflate-1.0.0.tgz", + "integrity": "sha512-YDoFpuZWu1VRXlsnlYMzKyVRITXj7Ej/V9gXQ2/pAe7X1J7M/RNOqaIYi6qUn+B7nGyB9pDXrv02dsB58d2ZAQ==", + "dev": true + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-gzip": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-gzip/-/is-gzip-1.0.0.tgz", + "integrity": "sha512-rcfALRIb1YewtnksfRIHGcIY93QnK8BIQ/2c9yDYcG/Y6+vRoJuTWBmmSEbyLLYtXm7q35pHOHbZFQBaLrhlWQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/jaguar": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/jaguar/-/jaguar-6.0.1.tgz", + "integrity": "sha512-WrJrwHHl4lHQa4dVG4fJTLxca19It/pTwtr5cnnUlY0MvWO0y1Y4dWn3ABVCEZzfd5gDbverVqin3tiZ/YloIQ==", + "dev": true, + "dependencies": { + "findit2": "^2.2.3", + "glob": "^7.1.0", + "gunzip-maybe": "^1.3.1", + "minimist": "^1.2.0", + "pipe-io": "^4.0.0", + "tar-fs": "^2.0.0", + "tar-stream": "^2.1.0", + "try-to-catch": "^3.0.0" + }, + "bin": { + "jaguar": "bin/jaguar.js" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "dev": true + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "3.2.10", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.2.10.tgz", + "integrity": "sha512-MhuzNwdURnZ1Cp4XTazr69K0BTizsBroX7Zx3UgDSVcZYKF/6p0CBe4EUb/hLqmzVhl0UpYfgRljQ4yxE+iCxA==", + "dev": true, + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/pako": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==", + "dev": true + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/peek-stream": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/peek-stream/-/peek-stream-1.1.3.tgz", + "integrity": "sha512-FhJ+YbOSBb9/rIl2ZeE/QHEsWn7PqNYt8ARAY3kIgNGOk13g9FGyIY6JIl/xB/3TFRVoTv5as0l11weORrTekA==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "duplexify": "^3.5.0", + "through2": "^2.0.3" + } + }, + "node_modules/pipe-io": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pipe-io/-/pipe-io-4.0.1.tgz", + "integrity": "sha512-Wj9G85wJCpIgHq7xd0g4/IDjrA51pxmd+m9AbTiC6zRmWzVC6jOJIUyf92r7/B2+NE6zwqZIz0BZr85xkc3/Sg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "dev": true, + "dependencies": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + } + }, + "node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/stream-shift": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", + "dev": true + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dev": true, + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-fs/node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar-stream/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/try-to-catch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/try-to-catch/-/try-to-catch-3.0.1.tgz", + "integrity": "sha512-hOY83V84Hx/1sCzDSaJA+Xz2IIQOHRvjxzt+F0OjbQGPZ6yLPLArMA0gw/484MlfUkQbCpKYMLX3VDCAjWKfzQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/web-streams-polyfill": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", + "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true, + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "17.6.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", + "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + } + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true + }, + "bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "browserify-zlib": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.1.4.tgz", + "integrity": "sha512-19OEpq7vWgsH6WkvkBJQDFvJS1uPcbFOQ4v9CU839dO+ZZXUZO6XpE6hNCqvlIIj+4fZvRiJ6DsAQ382GwiyTQ==", + "dev": true, + "requires": { + "pako": "~0.2.0" + } + }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true + }, + "cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "data-uri-to-buffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz", + "integrity": "sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA==", + "dev": true + }, + "duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "dev": true, + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "dev": true, + "requires": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + } + }, + "findit2": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/findit2/-/findit2-2.2.3.tgz", + "integrity": "sha512-lg/Moejf4qXovVutL0Lz4IsaPoNYMuxt4PA0nGqFxnJ1CTTGGlEO2wKgoDpwknhvZ8k4Q2F+eesgkLbG2Mxfog==", + "dev": true + }, + "formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "dev": true, + "requires": { + "fetch-blob": "^3.1.2" + } + }, + "fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "gunzip-maybe": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/gunzip-maybe/-/gunzip-maybe-1.4.2.tgz", + "integrity": "sha512-4haO1M4mLO91PW57BMsDFf75UmwoRX0GkdD+Faw+Lr+r/OZrOCS0pIBwOL1xCKQqnQzbNFGgK2V2CpBUPeFNTw==", + "dev": true, + "requires": { + "browserify-zlib": "^0.1.4", + "is-deflate": "^1.0.0", + "is-gzip": "^1.0.0", + "peek-stream": "^1.1.0", + "pumpify": "^1.3.3", + "through2": "^2.0.3" + } + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "is-deflate": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-deflate/-/is-deflate-1.0.0.tgz", + "integrity": "sha512-YDoFpuZWu1VRXlsnlYMzKyVRITXj7Ej/V9gXQ2/pAe7X1J7M/RNOqaIYi6qUn+B7nGyB9pDXrv02dsB58d2ZAQ==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-gzip": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-gzip/-/is-gzip-1.0.0.tgz", + "integrity": "sha512-rcfALRIb1YewtnksfRIHGcIY93QnK8BIQ/2c9yDYcG/Y6+vRoJuTWBmmSEbyLLYtXm7q35pHOHbZFQBaLrhlWQ==", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "jaguar": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/jaguar/-/jaguar-6.0.1.tgz", + "integrity": "sha512-WrJrwHHl4lHQa4dVG4fJTLxca19It/pTwtr5cnnUlY0MvWO0y1Y4dWn3ABVCEZzfd5gDbverVqin3tiZ/YloIQ==", + "dev": true, + "requires": { + "findit2": "^2.2.3", + "glob": "^7.1.0", + "gunzip-maybe": "^1.3.1", + "minimist": "^1.2.0", + "pipe-io": "^4.0.0", + "tar-fs": "^2.0.0", + "tar-stream": "^2.1.0", + "try-to-catch": "^3.0.0" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "dev": true + }, + "mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "dev": true + }, + "node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "dev": true + }, + "node-fetch": { + "version": "3.2.10", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.2.10.tgz", + "integrity": "sha512-MhuzNwdURnZ1Cp4XTazr69K0BTizsBroX7Zx3UgDSVcZYKF/6p0CBe4EUb/hLqmzVhl0UpYfgRljQ4yxE+iCxA==", + "dev": true, + "requires": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "pako": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", + "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true + }, + "peek-stream": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/peek-stream/-/peek-stream-1.1.3.tgz", + "integrity": "sha512-FhJ+YbOSBb9/rIl2ZeE/QHEsWn7PqNYt8ARAY3kIgNGOk13g9FGyIY6JIl/xB/3TFRVoTv5as0l11weORrTekA==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "duplexify": "^3.5.0", + "through2": "^2.0.3" + } + }, + "pipe-io": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pipe-io/-/pipe-io-4.0.1.tgz", + "integrity": "sha512-Wj9G85wJCpIgHq7xd0g4/IDjrA51pxmd+m9AbTiC6zRmWzVC6jOJIUyf92r7/B2+NE6zwqZIz0BZr85xkc3/Sg==", + "dev": true + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "dev": true, + "requires": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "stream-shift": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", + "dev": true + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dev": true, + "requires": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + }, + "dependencies": { + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } + } + }, + "tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "requires": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "try-to-catch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/try-to-catch/-/try-to-catch-3.0.1.tgz", + "integrity": "sha512-hOY83V84Hx/1sCzDSaJA+Xz2IIQOHRvjxzt+F0OjbQGPZ6yLPLArMA0gw/484MlfUkQbCpKYMLX3VDCAjWKfzQ==", + "dev": true + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "web-streams-polyfill": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", + "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", + "dev": true + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yargs": { + "version": "17.6.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", + "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", + "dev": true, + "requires": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + } + }, + "yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..955c189 --- /dev/null +++ b/package.json @@ -0,0 +1,34 @@ +{ + "name": "x_enchanting", + "version": "1.0.0", + "description": "Adds Enchanting Mechanics and API.", + "main": "index.js", + "type": "module", + "directories": { + "doc": "docs" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=8.0.0" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "push:ci": "node ./scripts/deploy", + "lua-diagnostics": "node ./scripts/lls-check" + }, + "repository": { + "type": "git", + "url": "git+https://juraj_vajda@bitbucket.org/minetest_gamers/x_enchanting.git" + }, + "author": "SaKeL", + "license": "LGPL-2.1-or-later", + "bugs": { + "url": "https://bitbucket.org/minetest_gamers/x_enchanting/issues" + }, + "homepage": "https://bitbucket.org/minetest_gamers/x_enchanting#readme", + "devDependencies": { + "jaguar": "^6.0.1", + "node-fetch": "^3.2.10", + "yargs": "^17.6.1" + } +} diff --git a/scripts/deploy.js b/scripts/deploy.js new file mode 100644 index 0000000..db93ac1 --- /dev/null +++ b/scripts/deploy.js @@ -0,0 +1,32 @@ +import fetch from 'node-fetch' +import yargs from 'yargs/yargs' +import {hideBin} from 'yargs/helpers' + +const argv = yargs(hideBin(process.argv)).argv + +try { + const body = { + method: 'git', + title: argv.title, + ref: 'master' + } + + const response = await fetch('https://content.minetest.net/api/packages/SaKeL/x_enchanting/releases/new/', { + method: 'POST', + body: JSON.stringify(body), + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${argv.token}` + } + }) + const data = await response.json() + + console.log(data) + + if (!data.success) { + process.exit(1) + } +} catch (error) { + console.log(error) + process.exit(1) +} diff --git a/scripts/lls-check.js b/scripts/lls-check.js new file mode 100644 index 0000000..2d4fa7d --- /dev/null +++ b/scripts/lls-check.js @@ -0,0 +1,93 @@ +import * as path from 'node:path' +import * as fs from 'node:fs' +import {exec} from 'node:child_process' +import yargs from 'yargs/yargs' +import {hideBin} from 'yargs/helpers' +import jaguar from 'jaguar' + +const argv = yargs(hideBin(process.argv)).argv +const cwd = process.cwd() +const logPath = path.join(cwd, 'logs') + +// Extract lua language server +const from = path.join(cwd, 'bin/lua-language-server-3.5.6-linux-x64.tar.gz'); +const to = path.join(cwd, 'bin', 'lua-language-server-3.5.6-linux-x64'); +const extract = jaguar.extract(from, to) + +// extract.on('file', (name) => { +// console.log(name) +// }) + +extract.on('start', () => { + console.log('Extracting...') +}) + +// extract.on('progress', (percent) => { +// console.log(percent + '%') +// }) + +extract.on('error', (error) => { + console.error(error) + process.exit(1) +}) + +extract.on('end', () => { + console.log('Extracting: Done') + + // Delete directory recursively + try { + fs.rmSync(logPath, { recursive: true, force: true }) + console.log(`Removed folder: ${logPath}`) + } catch (err) { + console.error(`Error while deleting ${logPath}.`) + console.error(err) + } + + let command = './bin/lua-language-server-3.5.6-linux-x64/bin/lua-language-server' + + if (argv.local) { + command = 'lua-language-server' + } + + exec(`${command} --logpath "${logPath}" --check "${cwd}"`, (error, stdout, stderr) => { + if (error) { + console.log(`error: ${error.message}`) + process.exit(1) + } + + if (stderr) { + console.log(`stderr: ${stderr}`) + process.exit(1) + } + + console.log(`\n${stdout}`) + + if (fs.existsSync('./logs/check.json')) { + const rawdata = fs.readFileSync('./logs/check.json') + const diagnosticsJson = JSON.parse(rawdata) + + Object.keys(diagnosticsJson).forEach((key) => { + console.log(key) + + diagnosticsJson[key].forEach((errObj) => { + console.log(`line: ${errObj.range.start.line} - ${errObj.message}`) + }) + }) + + console.error('Fix the errors/warnings above.') + process.exit(1) + } + + // Delete directory recursively + const llsFolder = path.join(cwd, 'bin', 'lua-language-server-3.5.6-linux-x64') + + try { + fs.rmSync(llsFolder, { recursive: true, force: true }) + console.log(`Removed folder: ${llsFolder}`) + } catch (err) { + console.error(`Error while deleting ${llsFolder}.`) + console.error(err) + process.exit(1) + } + }) +}) diff --git a/sounds/x_enchanting_enchant.ogg b/sounds/x_enchanting_enchant.ogg new file mode 100644 index 0000000..731bbc1 Binary files /dev/null and b/sounds/x_enchanting_enchant.ogg differ diff --git a/sounds/x_enchanting_scroll.1.ogg b/sounds/x_enchanting_scroll.1.ogg new file mode 100644 index 0000000..dee40fd Binary files /dev/null and b/sounds/x_enchanting_scroll.1.ogg differ diff --git a/sounds/x_enchanting_scroll.10.ogg b/sounds/x_enchanting_scroll.10.ogg new file mode 100644 index 0000000..9168ba0 Binary files /dev/null and b/sounds/x_enchanting_scroll.10.ogg differ diff --git a/sounds/x_enchanting_scroll.11.ogg b/sounds/x_enchanting_scroll.11.ogg new file mode 100644 index 0000000..c60ad52 Binary files /dev/null and b/sounds/x_enchanting_scroll.11.ogg differ diff --git a/sounds/x_enchanting_scroll.12.ogg b/sounds/x_enchanting_scroll.12.ogg new file mode 100644 index 0000000..0b1bc3c Binary files /dev/null and b/sounds/x_enchanting_scroll.12.ogg differ diff --git a/sounds/x_enchanting_scroll.13.ogg b/sounds/x_enchanting_scroll.13.ogg new file mode 100644 index 0000000..300ed5d Binary files /dev/null and b/sounds/x_enchanting_scroll.13.ogg differ diff --git a/sounds/x_enchanting_scroll.14.ogg b/sounds/x_enchanting_scroll.14.ogg new file mode 100644 index 0000000..e833a16 Binary files /dev/null and b/sounds/x_enchanting_scroll.14.ogg differ diff --git a/sounds/x_enchanting_scroll.2.ogg b/sounds/x_enchanting_scroll.2.ogg new file mode 100644 index 0000000..084a74f Binary files /dev/null and b/sounds/x_enchanting_scroll.2.ogg differ diff --git a/sounds/x_enchanting_scroll.3.ogg b/sounds/x_enchanting_scroll.3.ogg new file mode 100644 index 0000000..f31f6eb Binary files /dev/null and b/sounds/x_enchanting_scroll.3.ogg differ diff --git a/sounds/x_enchanting_scroll.4.ogg b/sounds/x_enchanting_scroll.4.ogg new file mode 100644 index 0000000..8e3e6a2 Binary files /dev/null and b/sounds/x_enchanting_scroll.4.ogg differ diff --git a/sounds/x_enchanting_scroll.5.ogg b/sounds/x_enchanting_scroll.5.ogg new file mode 100644 index 0000000..b6e5410 Binary files /dev/null and b/sounds/x_enchanting_scroll.5.ogg differ diff --git a/sounds/x_enchanting_scroll.6.ogg b/sounds/x_enchanting_scroll.6.ogg new file mode 100644 index 0000000..44ab34a Binary files /dev/null and b/sounds/x_enchanting_scroll.6.ogg differ diff --git a/sounds/x_enchanting_scroll.7.ogg b/sounds/x_enchanting_scroll.7.ogg new file mode 100644 index 0000000..d3e2a71 Binary files /dev/null and b/sounds/x_enchanting_scroll.7.ogg differ diff --git a/sounds/x_enchanting_scroll.8.ogg b/sounds/x_enchanting_scroll.8.ogg new file mode 100644 index 0000000..8c7f0e3 Binary files /dev/null and b/sounds/x_enchanting_scroll.8.ogg differ diff --git a/sounds/x_enchanting_scroll.9.ogg b/sounds/x_enchanting_scroll.9.ogg new file mode 100644 index 0000000..3c96beb Binary files /dev/null and b/sounds/x_enchanting_scroll.9.ogg differ diff --git a/sounds/x_enchanting_table_hard_footstep.1.ogg b/sounds/x_enchanting_table_hard_footstep.1.ogg deleted file mode 100644 index 0a08efa..0000000 Binary files a/sounds/x_enchanting_table_hard_footstep.1.ogg and /dev/null differ diff --git a/sounds/x_enchanting_table_hard_footstep.2.ogg b/sounds/x_enchanting_table_hard_footstep.2.ogg deleted file mode 100644 index be52a87..0000000 Binary files a/sounds/x_enchanting_table_hard_footstep.2.ogg and /dev/null differ diff --git a/sounds/x_enchanting_table_hard_footstep.3.ogg b/sounds/x_enchanting_table_hard_footstep.3.ogg deleted file mode 100644 index a342787..0000000 Binary files a/sounds/x_enchanting_table_hard_footstep.3.ogg and /dev/null differ diff --git a/sounds/x_enchanting_table_place_node_hard.1.ogg b/sounds/x_enchanting_table_place_node_hard.1.ogg deleted file mode 100644 index 9f97fac..0000000 Binary files a/sounds/x_enchanting_table_place_node_hard.1.ogg and /dev/null differ diff --git a/sounds/x_enchanting_table_place_node_hard.2.ogg b/sounds/x_enchanting_table_place_node_hard.2.ogg deleted file mode 100644 index 1d3b3de..0000000 Binary files a/sounds/x_enchanting_table_place_node_hard.2.ogg and /dev/null differ diff --git a/table.lua b/table.lua index 4d7ba74..2a9b145 100644 --- a/table.lua +++ b/table.lua @@ -1,33 +1,9 @@ screwdriver = minetest.global_exists('screwdriver') and screwdriver --[[@as MtgScrewdriver]] -local scroll_animations = { - scroll_open = { { x = 1, y = 40 }, 80, 0, false }, - scroll_close = { { x = 45, y = 84 }, 80, 0, false }, - scroll_open_idle = { { x = 41, y = 42 }, 0, 0, false }, - scroll_closed_idle = { { x = 43, y = 43 }, 0, 0, false } -} +---- +--- Table Node +---- -local function get_formspec(pos) - local spos = pos.x .. ',' .. pos.y .. ',' .. pos.z - local formspec = - 'size[8,9]' .. - 'label[0, 0;Enchant]' .. - ---@diagnostic disable-next-line: codestyle-check - 'model[0,0;2,3;x_enchanting_table;x_enchanting_scroll.b3d;x_enchanting_scroll_mesh.png,x_enchanting_scroll_handles_mesh.png,x_enchanting_scroll_mesh.png;89,0;false;false;' .. scroll_animations.scroll_open_idle[1].x .. ',' .. scroll_animations.scroll_open_idle[1].y .. ';0]' .. - 'list[nodemeta:' .. spos .. ';item;0, 2.5;1, 1;]' .. - 'image[1,2.5;1,1;x_enchanting_trade_slot.png;]' .. - 'list[nodemeta:' .. spos .. ';trade;1, 2.5;1, 1;]' .. - 'list[current_player;main;0, 4.85;8, 1;]' .. - 'list[current_player;main;0, 6.08;8, 3;8]' .. - 'listring[nodemeta:' .. spos .. ';item]' .. - 'listring[nodemeta:' .. spos .. ';trade]' .. - 'listring[current_player;main]' .. - default.get_hotbar_bg(0, 4.85) - - return formspec -end - ----Table Node minetest.register_node('x_enchanting:table', { description = 'Enchating Table', short_description = 'Enchating Table', @@ -48,15 +24,15 @@ minetest.register_node('x_enchanting:table', { }, sounds = { footstep = { - name = 'x_enchanting_table_hard_footstep', + name = 'x_enchanting_scroll', gain = 0.2 }, dug = { - name = 'x_enchanting_table_hard_footstep', + name = 'x_enchanting_scroll', gain = 1.0 }, place = { - name = 'x_enchanting_table_place_node_hard', + name = 'x_enchanting_scroll', gain = 1.0 } }, @@ -105,15 +81,34 @@ minetest.register_node('x_enchanting:table', { return itemstack end - minetest.sound_play('default_dig_choppy', { + minetest.sound_play('x_enchanting_scroll', { gain = 0.3, pos = pos, max_hear_distance = 10 }, true) - local formspec = get_formspec(pos) + -- bookshelfs + local bookshelfs = minetest.find_nodes_in_area( + { x = pos.x - 2, y = pos.y, z = pos.z - 2 }, + { x = pos.x + 2, y = pos.y + 2, z = pos.z + 2 }, + { 'default:bookshelf', 'group:bookshelf' } + ) - minetest.show_formspec(clicker:get_player_name(), 'x_enchanting:table', formspec) + local inv = minetest.get_meta(pos):get_inventory() + + if not inv:is_empty('item') then + local item_stack = inv:get_stack('item', 1) + local data = XEnchanting:get_enchantment_data(#bookshelfs, minetest.registered_tools[item_stack:get_name()]) + local formspec = XEnchanting:get_formspec(pos, p_name, data) + + minetest.show_formspec(p_name, 'x_enchanting:table', formspec) + else + local formspec = XEnchanting:get_formspec(pos, p_name) + + minetest.show_formspec(p_name, 'x_enchanting:table', formspec) + end + + return itemstack end, ---@param pos Vector ---@param intensity? number @@ -168,7 +163,7 @@ minetest.register_node('x_enchanting:table', { end local particlespawner_def = { - amount = 30, + amount = 50, time = 5, minpos = { x = pos.x - 0.1, y = pos.y + 0.2, z = pos.z - 0.1 }, maxpos = { x = pos.x + 0.1, y = pos.y + 0.3, z = pos.z + 0.1 }, @@ -187,7 +182,7 @@ minetest.register_node('x_enchanting:table', { if minetest.has_feature({ dynamic_add_media_table = true, particlespawner_tweenable = true }) then -- new syntax, after v5.6.0 particlespawner_def = { - amount = 30, + amount = 50, time = 5, size = { min = 0.1, @@ -228,9 +223,6 @@ minetest.register_node('x_enchanting:table', { return true end - -- just for testing - XEnchanting:get_base_enchantment_level(#bookshelfs, minetest.registered_tools['default:pick_mese']) - -- symbol particles for i = 1, 10, 1 do local pos_random = bookshelfs[math.random(1, #bookshelfs)] @@ -268,16 +260,184 @@ minetest.register_node('x_enchanting:table', { end end end, + ---@param pos Vector + ---@param listname string + ---@param index number + ---@param stack ItemStack + ---@param player ObjectRef + allow_metadata_inventory_put = function(pos, listname, index, stack, player) + local st_meta = stack:get_meta() + local st_name = stack:get_name() + local is_enchanted = st_meta:get_int('is_enchanted') - -- on_receive_fields = enchanting.fields, - -- on_metadata_inventory_put = enchanting.on_put, - -- on_metadata_inventory_take = enchanting.on_take, - -- allow_metadata_inventory_put = enchanting.put, - -- allow_metadata_inventory_take = enchanting.take, - -- allow_metadata_inventory_move = function() return 0 end, + if listname == 'item' + and minetest.get_item_group(st_name, 'enchantability') > 0 + and is_enchanted ~= 1 + then + return stack:get_count() + elseif listname == 'trade' + and ( + st_name == 'default:mese_crystal' + or minetest.get_item_group(st_name, 'enchanting_trade') > 0 + ) + and is_enchanted ~= 1 + then + return stack:get_count() + end + + return 0 + end, + ---@param pos Vector + ---@param listname string + ---@param index number + ---@param stack ItemStack + ---@param player ObjectRef + allow_metadata_inventory_take = function(pos, listname, index, stack, player) + local st_name = stack:get_name() + + if listname == 'item' then + return stack:get_count() + elseif listname == 'trade' + and ( + st_name == 'default:mese_crystal' + or minetest.get_item_group(st_name, 'enchanting_trade') > 0 + ) + then + return stack:get_count() + end + + return 0 + end, + ---@param pos Vector + ---@param from_list string + ---@param from_index number + ---@param to_list string + ---@param to_index number + ---@param count number + ---@param player ObjectRef + allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player) + return 0 + end, + ---@param pos Vector + ---@param listname string + ---@param index number + ---@param stack ItemStack + ---@param player ObjectRef + on_metadata_inventory_put = function(pos, listname, index, stack, player) + local p_name = player:get_player_name() + local inv = minetest.get_meta(pos):get_inventory() + + if not inv:is_empty('item') then + -- bookshelfs + local bookshelfs = minetest.find_nodes_in_area( + { x = pos.x - 2, y = pos.y, z = pos.z - 2 }, + { x = pos.x + 2, y = pos.y + 2, z = pos.z + 2 }, + { 'default:bookshelf' } + ) + + local item_stack = inv:get_stack('item', 1) + local data = XEnchanting:get_enchantment_data(#bookshelfs, minetest.registered_tools[item_stack:get_name()]) + local formspec = XEnchanting:get_formspec(pos, p_name, data) + + minetest.show_formspec(p_name, 'x_enchanting:table', formspec) + else + local formspec = XEnchanting:get_formspec(pos, p_name) + + minetest.show_formspec(p_name, 'x_enchanting:table', formspec) + end + end, + ---@param pos Vector + ---@param listname string + ---@param index number + ---@param stack ItemStack + ---@param player ObjectRef + on_metadata_inventory_take = function(pos, listname, index, stack, player) + local p_name = player:get_player_name() + local inv = minetest.get_meta(pos):get_inventory() + + if not inv:is_empty('item') then + -- bookshelfs + local bookshelfs = minetest.find_nodes_in_area( + { x = pos.x - 2, y = pos.y, z = pos.z - 2 }, + { x = pos.x + 2, y = pos.y + 2, z = pos.z + 2 }, + { 'default:bookshelf' } + ) + + local item_stack = inv:get_stack('item', 1) + local data = XEnchanting:get_enchantment_data(#bookshelfs, minetest.registered_tools[item_stack:get_name()]) + local formspec = XEnchanting:get_formspec(pos, p_name, data) + + minetest.show_formspec(p_name, 'x_enchanting:table', formspec) + else + local formspec = XEnchanting:get_formspec(pos, p_name) + + minetest.show_formspec(p_name, 'x_enchanting:table', formspec) + end + end }) ----Scroll Entity +-- form receive fields +---@param player ObjectRef +---@param formname string +---@param fields table +minetest.register_on_player_receive_fields(function(player, formname, fields) + local p_name = player:get_player_name() + + if formname ~= 'x_enchanting:table' or fields.quit then + XEnchanting.form_context[p_name] = nil + return + end + + local selected_slot + + if fields.slot_1 and fields.slot_1 ~= '' then + selected_slot = 1 + elseif fields.slot_2 and fields.slot_2 ~= '' then + selected_slot = 2 + elseif fields.slot_3 and fields.slot_3 ~= '' then + selected_slot = 3 + end + + if not XEnchanting.form_context[p_name] or not selected_slot then + return + end + + local pos = XEnchanting.form_context[p_name].pos + local inv = minetest.get_meta(pos):get_inventory() + + if inv:is_empty('trade') or inv:is_empty('item') then + return + end + + local trade_stack = inv:get_stack('trade', 1) + local data = XEnchanting.form_context[p_name].data + + if trade_stack:get_count() < selected_slot or not data then + return + end + + local item_stack = inv:get_stack('item', 1) + local is_enchanted = item_stack:get_meta():get_int('is_enchanted') + + if is_enchanted == 1 then + return + end + + -- Enchant item + XEnchanting:set_enchanted_tool( + pos, + item_stack, + data.slots[selected_slot].tool_cap_data.tool_capabilities, + data.slots[selected_slot].tool_cap_data.enchantments_desc, + selected_slot, + p_name + ) +end) + +---- +--- Entity (Scroll) +---- + minetest.register_entity('x_enchanting:table_scroll', { initial_properties = { visual = 'mesh', @@ -374,10 +534,10 @@ minetest.register_entity('x_enchanting:table_scroll', { -- scroll open/close animation if self._player and self._scroll_closed then self._scroll_closed = false - self.object:set_animation(unpack(scroll_animations.scroll_open)) + self.object:set_animation(unpack(XEnchanting.scroll_animations.scroll_open)) elseif not self._player and not self._scroll_closed then self._scroll_closed = true - self.object:set_animation(unpack(scroll_animations.scroll_close)) + self.object:set_animation(unpack(XEnchanting.scroll_animations.scroll_close)) end end @@ -404,3 +564,27 @@ minetest.register_entity('x_enchanting:table_scroll', { return true end }) + +---- +-- Recipe +--- + +if minetest.get_modpath('xdecor') then + minetest.register_craft({ + output = 'x_enchanting:table', + recipe = { + { 'default:book', '', '' }, + { 'default:diamond', 'default:obsidian', 'default:diamond' }, + { 'default:obsidian', 'default:obsidian', 'default:obsidian' } + } + }) +else + minetest.register_craft({ + output = 'x_enchanting:table', + recipe = { + { '', 'default:book', '' }, + { 'default:diamond', 'default:obsidian', 'default:diamond' }, + { 'default:obsidian', 'default:obsidian', 'default:obsidian' } + } + }) +end diff --git a/textures/x_enchanting_image_button.png b/textures/x_enchanting_image_button.png new file mode 100644 index 0000000..dcf3d20 Binary files /dev/null and b/textures/x_enchanting_image_button.png differ diff --git a/textures/x_enchanting_image_button_disabled.png b/textures/x_enchanting_image_button_disabled.png new file mode 100644 index 0000000..6f6141f Binary files /dev/null and b/textures/x_enchanting_image_button_disabled.png differ diff --git a/textures/x_enchanting_image_trade_1.png b/textures/x_enchanting_image_trade_1.png new file mode 100644 index 0000000..1c5b702 Binary files /dev/null and b/textures/x_enchanting_image_trade_1.png differ diff --git a/textures/x_enchanting_image_trade_2.png b/textures/x_enchanting_image_trade_2.png new file mode 100644 index 0000000..e613a47 Binary files /dev/null and b/textures/x_enchanting_image_trade_2.png differ diff --git a/textures/x_enchanting_image_trade_3.png b/textures/x_enchanting_image_trade_3.png new file mode 100644 index 0000000..5aac4c1 Binary files /dev/null and b/textures/x_enchanting_image_trade_3.png differ diff --git a/types/item.type.lua b/types/item.type.lua index 0ec0b11..bd74731 100644 --- a/types/item.type.lua +++ b/types/item.type.lua @@ -29,6 +29,7 @@ ---@field on_use fun(itemstack: ItemStack, user: ObjectRef|nil, pointed_thing: PointedThingDef): ItemStack|nil default: nil. When user pressed the 'punch/mine' key with the item in hand. Function must return either nil if inventory shall not be modified, or an itemstack to replace the original itemstack. e.g. itemstack:take_item(); return itemstack. Otherwise, the function is free to do what it wants. The user may be any ObjectRef or nil. The default functions handle regular use cases. ---@field after_use fun(itemstack: ItemStack, user: ObjectRef|nil, node: NodeDef, digparams: DigParamsDef): ItemStack|nil default: nil. If defined, should return an itemstack and will be called instead of wearing out the item (if tool). If returns nil, does nothing. ---@field soil table Only for farming +---@field name string ---Tool capabilities definition ---@class ToolCapabilitiesDef diff --git a/types/xenchanting.type.lua b/types/xenchanting.type.lua index 990b007..a721ac0 100644 --- a/types/xenchanting.type.lua +++ b/types/xenchanting.type.lua @@ -1,3 +1,58 @@ ---@diagnostic disable: codestyle-check ----Base class XBows + +---Base class XEnchanting ---@class XEnchanting +---@field tools_enchantability table Add enchantability to default tools. key/value = tool_name/enchantibility value +---@field roman_numbers table Convert Arabic numbers to Roman numbers +---@field enchantment_defs table<'sharpness' | 'fortune' | 'unbreaking' | 'efficiency', EnchantmentDef> +---@field has_tool_group fun(self: XEnchanting, name: string): string | boolean Check if tool has one of the known tool groups, returns `false` otherwise. +---@field set_tool_enchantability fun(self: XEnchanting, tool_def: ItemDef): nil Sets `enchantibility` group and values from base table (`XEnchanting.tools_enchantability`) to all registered tools (atching known group names). If tool has already `enchantibility` group defined it will take the defined value insted. +---@field get_enchanted_tool_capabilities fun(self: XEnchanting, tool_def: ItemDef, enchantments: Enchantments[]): GetEnchantedToolCapabilitiesReturn Applies enchantments to item tool capabilities. +---@field set_enchanted_tool fun(self: XEnchanting, pos: Vector, itemstack: ItemStack, capabilities: ToolCapabilitiesDef, description: string, level: number, player_name: string): nil Set choosen enchantment and its modified tool capabilities to itemstack and `item` inventory. This will also get new `randomseed`. +---@field get_enchantment_data fun(self: XEnchanting, nr_of_bookshelfs: number, tool_def: ItemDef): EnchantmentData Algoritm to get aplicable random enchantments. +---@field get_formspec fun(self: XEnchanting, pos, player_name, data): string Builds and returns `formspec` string + + +---Enchantment definition +---@class EnchantmentDef +---@field name string Readable name of the enchantment +---@field final_level_range table> Level range +---@field level_def table Level bonus +---@field weight number Enchantment weight +---@field randomseed number Math random seed. Will change after item was enchanted. +---@field form_context table Additional form data for player. +---@field scroll_animations table Parameters for `ObjectRef` `set_animation` method + + +---Form context +---@class FormContextDef +---@field pos Vector Formspec/node form position +---@field data table Enchantment data + + +---@class GetEnchantedToolCapabilitiesReturn +---@field tool_capabilities ToolCapabilitiesDef +---@field enchantments_desc string +---@field enchantments_desc_masked string + + +---@class EnchantmentData +---@field slots EnchantmentDataSlot[] + + +---@class Enchantments +---@field id string +---@field value number +---@field level number + + +---@class ToolCapData +---@field enchantments_desc string Masket description before enchating +---@field enchantments_desc_masked string Description added to item description definition after enchanting +---@field tool_capabilities ToolCapabilitiesDef Modified tool capabilities with applied enchantment + + +---@class EnchantmentDataSlot +---@field final_enchantments Enchantments[] +---@field tool_cap_data ToolCapData +---@field level number