From 012cbfa201b5a7295c8305cd50148dcba1591034 Mon Sep 17 00:00:00 2001 From: xefensor Date: Tue, 11 Aug 2026 02:21:31 +0200 Subject: [PATCH 01/11] Implement ore and tool progression --- CHANGELOG.md | 6 + docs/internal/README.md | 2 +- docs/internal/design_implementation_status.md | 16 +- docs/internal/retold_design_risks.md | 2 +- docs/internal/retold_mod_system.md | 33 +- docs/internal/retold_roadmap.md | 2 +- docs/internal/tool_armor_ore_progression.md | 153 ++- .../retold/gametest/RetoldGameTests.java | 2 + .../retold/mixin/CampfirePlacementMixin.java | 28 + .../ItemStackDiamondDurabilityMixin.java | 24 + .../retold/module/RetoldFoundationModule.java | 6 + .../RetoldCampfireProgressionEvents.java | 88 ++ .../progression/RetoldDiamondDurability.java | 47 + .../RetoldLeafStickLootModifier.java | 89 ++ .../progression/RetoldLootModifiers.java | 33 + .../RetoldToolProgressionEvents.java | 90 ++ .../RetoldToolProgressionGameTests.java | 949 ++++++++++++++++++ .../retold/registry/RetoldBlocks.java | 138 +++ .../registry/RetoldCreativeModeTabs.java | 29 + .../xefensor/retold/registry/RetoldTags.java | 64 ++ .../assets/minecraft/lang/en_us.json | 4 + .../assets/retold/items/flint_multi_tool.json | 6 + .../assets/retold/items/steel_axe.json | 6 + .../assets/retold/items/steel_boots.json | 6 + .../assets/retold/items/steel_chestplate.json | 6 + .../assets/retold/items/steel_helmet.json | 6 + .../assets/retold/items/steel_hoe.json | 6 + .../assets/retold/items/steel_ingot.json | 6 + .../assets/retold/items/steel_leggings.json | 6 + .../assets/retold/items/steel_pickaxe.json | 6 + .../assets/retold/items/steel_shovel.json | 6 + .../assets/retold/items/steel_sword.json | 6 + .../resources/assets/retold/lang/en_us.json | 11 + .../retold/models/item/flint_multi_tool.json | 6 + .../data/c/tags/item/ingots/steel.json | 5 + .../data/minecraft/recipe/smoker.json | 15 + .../data/minecraft/tags/item/axes.json | 5 + .../data/minecraft/tags/item/chest_armor.json | 5 + .../data/minecraft/tags/item/foot_armor.json | 5 + .../data/minecraft/tags/item/head_armor.json | 5 + .../data/minecraft/tags/item/hoes.json | 5 + .../data/minecraft/tags/item/leg_armor.json | 5 + .../data/minecraft/tags/item/pickaxes.json | 5 + .../data/minecraft/tags/item/shovels.json | 5 + .../data/minecraft/tags/item/swords.json | 5 + .../worldgen/placed_feature/ore_copper.json | 27 + .../placed_feature/ore_copper_large.json | 27 + .../loot_modifiers/more_leaf_sticks.json | 4 + ...brick_from_campfire_cooking_clay_ball.json | 9 + .../recipe/charcoal_from_smoking_logs.json | 9 + .../copper_ingot_from_smoking_copper_ore.json | 10 + ...got_from_smoking_deepslate_copper_ore.json | 10 + .../copper_ingot_from_smoking_raw_copper.json | 10 + .../data/retold/recipe/flint_multi_tool.json | 15 + .../data/retold/recipe/steel_axe.json | 16 + .../data/retold/recipe/steel_boots.json | 14 + .../data/retold/recipe/steel_chestplate.json | 15 + .../data/retold/recipe/steel_helmet.json | 14 + .../data/retold/recipe/steel_hoe.json | 16 + .../steel_ingot_from_blasting_iron_ingot.json | 11 + .../data/retold/recipe/steel_leggings.json | 15 + .../data/retold/recipe/steel_pickaxe.json | 16 + .../data/retold/recipe/steel_shovel.json | 16 + .../data/retold/recipe/steel_sword.json | 16 + .../block/incorrect_for_flint_multi_tool.json | 6 + .../tags/block/incorrect_for_steel_tool.json | 5 + .../tags/block/mineable/flint_multi_tool.json | 17 + .../retold/tags/block/steel_tier_blocks.json | 21 + .../flint_multi_tool_repair_materials.json | 5 + .../fragile_unenchanted_diamond_armor.json | 8 + .../fragile_unenchanted_diamond_tools.json | 10 + .../tags/item/steel_repair_materials.json | 5 + .../retold/villager_teaching/armorer.json | 16 + .../retold/villager_teaching/toolsmith.json | 35 +- .../retold/villager_teaching/weaponsmith.json | 18 +- src/main/resources/retold.mixins.json | 2 + 76 files changed, 2306 insertions(+), 65 deletions(-) create mode 100644 src/main/java/cz/xefensor/retold/mixin/CampfirePlacementMixin.java create mode 100644 src/main/java/cz/xefensor/retold/mixin/ItemStackDiamondDurabilityMixin.java create mode 100644 src/main/java/cz/xefensor/retold/progression/RetoldCampfireProgressionEvents.java create mode 100644 src/main/java/cz/xefensor/retold/progression/RetoldDiamondDurability.java create mode 100644 src/main/java/cz/xefensor/retold/progression/RetoldLeafStickLootModifier.java create mode 100644 src/main/java/cz/xefensor/retold/progression/RetoldLootModifiers.java create mode 100644 src/main/java/cz/xefensor/retold/progression/RetoldToolProgressionEvents.java create mode 100644 src/main/java/cz/xefensor/retold/progression/RetoldToolProgressionGameTests.java create mode 100644 src/main/resources/assets/minecraft/lang/en_us.json create mode 100644 src/main/resources/assets/retold/items/flint_multi_tool.json create mode 100644 src/main/resources/assets/retold/items/steel_axe.json create mode 100644 src/main/resources/assets/retold/items/steel_boots.json create mode 100644 src/main/resources/assets/retold/items/steel_chestplate.json create mode 100644 src/main/resources/assets/retold/items/steel_helmet.json create mode 100644 src/main/resources/assets/retold/items/steel_hoe.json create mode 100644 src/main/resources/assets/retold/items/steel_ingot.json create mode 100644 src/main/resources/assets/retold/items/steel_leggings.json create mode 100644 src/main/resources/assets/retold/items/steel_pickaxe.json create mode 100644 src/main/resources/assets/retold/items/steel_shovel.json create mode 100644 src/main/resources/assets/retold/items/steel_sword.json create mode 100644 src/main/resources/assets/retold/models/item/flint_multi_tool.json create mode 100644 src/main/resources/data/c/tags/item/ingots/steel.json create mode 100644 src/main/resources/data/minecraft/recipe/smoker.json create mode 100644 src/main/resources/data/minecraft/tags/item/axes.json create mode 100644 src/main/resources/data/minecraft/tags/item/chest_armor.json create mode 100644 src/main/resources/data/minecraft/tags/item/foot_armor.json create mode 100644 src/main/resources/data/minecraft/tags/item/head_armor.json create mode 100644 src/main/resources/data/minecraft/tags/item/hoes.json create mode 100644 src/main/resources/data/minecraft/tags/item/leg_armor.json create mode 100644 src/main/resources/data/minecraft/tags/item/pickaxes.json create mode 100644 src/main/resources/data/minecraft/tags/item/shovels.json create mode 100644 src/main/resources/data/minecraft/tags/item/swords.json create mode 100644 src/main/resources/data/minecraft/worldgen/placed_feature/ore_copper.json create mode 100644 src/main/resources/data/minecraft/worldgen/placed_feature/ore_copper_large.json create mode 100644 src/main/resources/data/retold/loot_modifiers/more_leaf_sticks.json create mode 100644 src/main/resources/data/retold/recipe/brick_from_campfire_cooking_clay_ball.json create mode 100644 src/main/resources/data/retold/recipe/charcoal_from_smoking_logs.json create mode 100644 src/main/resources/data/retold/recipe/copper_ingot_from_smoking_copper_ore.json create mode 100644 src/main/resources/data/retold/recipe/copper_ingot_from_smoking_deepslate_copper_ore.json create mode 100644 src/main/resources/data/retold/recipe/copper_ingot_from_smoking_raw_copper.json create mode 100644 src/main/resources/data/retold/recipe/flint_multi_tool.json create mode 100644 src/main/resources/data/retold/recipe/steel_axe.json create mode 100644 src/main/resources/data/retold/recipe/steel_boots.json create mode 100644 src/main/resources/data/retold/recipe/steel_chestplate.json create mode 100644 src/main/resources/data/retold/recipe/steel_helmet.json create mode 100644 src/main/resources/data/retold/recipe/steel_hoe.json create mode 100644 src/main/resources/data/retold/recipe/steel_ingot_from_blasting_iron_ingot.json create mode 100644 src/main/resources/data/retold/recipe/steel_leggings.json create mode 100644 src/main/resources/data/retold/recipe/steel_pickaxe.json create mode 100644 src/main/resources/data/retold/recipe/steel_shovel.json create mode 100644 src/main/resources/data/retold/recipe/steel_sword.json create mode 100644 src/main/resources/data/retold/tags/block/incorrect_for_flint_multi_tool.json create mode 100644 src/main/resources/data/retold/tags/block/incorrect_for_steel_tool.json create mode 100644 src/main/resources/data/retold/tags/block/mineable/flint_multi_tool.json create mode 100644 src/main/resources/data/retold/tags/block/steel_tier_blocks.json create mode 100644 src/main/resources/data/retold/tags/item/flint_multi_tool_repair_materials.json create mode 100644 src/main/resources/data/retold/tags/item/fragile_unenchanted_diamond_armor.json create mode 100644 src/main/resources/data/retold/tags/item/fragile_unenchanted_diamond_tools.json create mode 100644 src/main/resources/data/retold/tags/item/steel_repair_materials.json diff --git a/CHANGELOG.md b/CHANGELOG.md index b783382..644addc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,10 @@ Each release should be readable in two passes: ### Player-Facing +- The survival opening now begins with Sticks and Flint instead of punching logs. Leaves have an additional 20% chance to drop 1–2 Sticks, increasing by five percentage points per Fortune level; shears and Silk Touch retain their normal leaf-block harvest without the extra drop. Logs require a suitable tool, the 2x2 Flint Multi-tool harvests the first wood, exposed Copper, and soft early stone, and vanilla Wooden and Stone tool recipes no longer bypass the material ladder. Copper generation now makes six vein attempts per chunk instead of sixteen while preserving normal vein sizes, reducing cave-wall clutter without making each discovery unrewarding. Copper Pickaxes can harvest normal Stone for Cobblestone, but do so at 25% speed until Iron makes ordinary mining practical. +- Campfires are now crafted from three Sticks and three Logs without Coal or Flint and begin unlit immediately when placed, without briefly flashing their lit appearance. Using a bare Flint lights one and consumes that Flint in Survival, while Flint and Steel retains its normal durability-based ignition. Clay Balls fire into Bricks on a Campfire; eight Bricks in a ring then craft the Brick Furnace, Retold's renamed Smoker. It keeps food cooking, makes Charcoal from burnable logs, and processes Raw Copper and both Copper ores so players can reach Copper before obtaining Cobblestone for a normal Furnace. +- Blast Furnaces now process Iron Ingots directly into Steel Ingots using any ordinary fuel. Steel provides a full Pickaxe, Axe, Shovel, Hoe, Sword, and armor tier between Iron and Diamond. Copper and Iron remain painfully slow on Deepslate-family blocks, while Steel restores full deep-mining speed, harvests deep Diamond Ore, and still leaves Obsidian to Diamond. +- Unenchanted Diamond tools and Spears now have only 64 durability, while unenchanted Diamond player armor has leather-like 6x durability. Any enchantment immediately restores full vanilla Diamond durability; removing every enchantment makes the item fragile again. A heavily damaged item stripped beyond that fragile limit retains one final use instead of becoming invalid immediately. - The End no longer produces its periodic celestial flashes, temporary brightness pulses, or delayed flash sounds. Retold's generated End sky remains unchanged. - Trial Chambers, Ancient Cities, and the Deep Dark no longer generate in newly explored terrain. Their blocks, items, mobs, biomes, and already-generated content remain available. - Ruined Nether portals no longer generate with loot chests. @@ -20,6 +24,8 @@ Each release should be readable in two passes: ### Technical +- Added the 48-durability Flint Multi-tool and provisional Steel material with data-driven mining, repair, common-ingot, enchantment-family, and armor tags. A global loot modifier supplies additional Sticks from every block in `minecraft:leaves`, and placed-feature overrides reduce both ordinary and Dripstone Copper attempts from sixteen to six per chunk. Exact Wooden/Stone recipes are removed during recipe loading; Armorer, Toolsmith, and Weaponsmith lessons follow the material ladder. Five focused GameTests cover leaf Stick supply, reduced Copper placement across seeded chunk-border samples, the unfueled Campfire recipe and ignition behavior, harvest tiers through Steel, Copper/Deepslate pacing, starter and equipment crafting, Brick Furnace processing, normal Iron-to-Steel blasting, and Furnace availability. +- Added tag-driven dynamic Diamond durability through a narrow `ItemStack.getMaxDamage` hook and a named progression policy. Focused coverage verifies fragile tool/armor values, enchantment restoration, removal regression, vanilla-tag preservation, and the over-damaged stripped-item safeguard. - Added a client-only vanilla-End hook that clears `EndFlashState` after level construction, suppressing all flash rendering, lightmap, and sound paths while preserving the End skybox and leaving other End-style dimensions untouched. - Replaced the vanilla Trial Chamber and Ancient City biome tags with empty tags so the structures remain registered but have no eligible generation biomes. A narrow Overworld biome-builder hook omits the Deep Dark mapping from the default climate preset without unregistering the biome. Added focused GameTest coverage for each boundary. - Added a ruined-portal placement processor that omits template chests without affecting chests or other containers elsewhere, with focused GameTest coverage. diff --git a/docs/internal/README.md b/docs/internal/README.md index 11e62fb..d3e3975 100644 --- a/docs/internal/README.md +++ b/docs/internal/README.md @@ -26,7 +26,7 @@ Use the files this way: | [`retold_roadmap.md`](retold_roadmap.md) | active developer direction, priorities, undecided items, and not-planned items | | [`design_principles.md`](design_principles.md) | developer-confirmed high-level design rules used to judge future Retold systems | | [`living_world_and_settlements.md`](living_world_and_settlements.md) | confirmed design for roads, environmental reclaiming/weathering, village generation/growth, professions, logistics, trade, magic/energy, and player-village reputation | -| [`tool_armor_ore_progression.md`](tool_armor_ore_progression.md) | confirmed material/tool/armor/station progression: Flint Multi-tool opening, Clay Furnace/Copper, Furnace/Iron, Blast Furnace/Steel, Diamond enchanting, Netherite, and Aenderite direction | +| [`tool_armor_ore_progression.md`](tool_armor_ore_progression.md) | confirmed material/tool/armor/station progression: Flint Multi-tool and Campfire opening, Brick Furnace/Copper, Furnace/Iron, Blast Furnace/Steel, Diamond enchanting, Netherite, and Aenderite direction | | [`golem_equipment_design.md`](golem_equipment_design.md) | confirmed design for pacifist-villager metalworking, oversized Iron Golem armor/weapons, block-scale material costs, and settlement defense investment | | [`enchanting_design.md`](enchanting_design.md) | confirmed enchanting direction: player-learned SGA language, domain/effect/modifier words, energy-based levels, discovery, and known-enchantment recording | | [`enchanting_test_guide.md`](enchanting_test_guide.md) | spoiler-heavy developer checklist with every spell word, maximum level, compatible test item, cost, and expected success/failure behavior | diff --git a/docs/internal/design_implementation_status.md b/docs/internal/design_implementation_status.md index 3786541..285b70b 100644 --- a/docs/internal/design_implementation_status.md +++ b/docs/internal/design_implementation_status.md @@ -34,7 +34,7 @@ Status labels: ## Current Developer Direction Source -Last design clarification: 2026-08-03. +Last design clarification: 2026-08-11. Last documentation consolidation pass: 2026-07-17. Active developer direction lives in [`retold_roadmap.md`](retold_roadmap.md). This status tracker applies that direction to individual original-design rows so implementation status stays visible without duplicating the roadmap. @@ -162,12 +162,14 @@ Largest missing or partial design areas: | Design item | Status | Current implementation | | --- | --- | --- | -| Wood cannot be obtained by hand | Not implemented | -| Flint multi-tool | Not implemented | -| Flint/copper/iron/steel/diamond tool progression | Not implemented | -| New station progression: clay furnace, stone furnace, blast furnace, enchanted station | Not implemented | -| Leather/copper/iron/steel/diamond armor progression | Not implemented | -| Diamond tools weak unless enchanted | Not implemented | +| Leaves provide opening Sticks | Implemented / needs in-game verification | Every block in `minecraft:leaves` receives an additional 20% chance for 1–2 Sticks, with +5 percentage points per Fortune level. Shears and Silk Touch are excluded. A focused real-loot-table GameTest samples the increased base supply, Fortune III improvement, and both harvest exclusions; natural decay, explosions, modded leaves, and first-spawn pacing remain to be verified in-game. | +| Wood cannot be obtained by hand | Implemented / needs in-game verification | A harvest check prevents logs from dropping unless the held item is a correct harvesting tool. Focused GameTest coverage verifies hand denial and Flint Multi-tool success; naturally verify block breaking, drops, Adventure mode, and common modded logs. | +| Flint multi-tool | Implemented / needs in-game verification | The 2x2 two-Flint/one-Stick recipe, 48-durability combined axe/shovel/primitive Copper tool, repair tag, creative placement, language entry, and provisional vanilla-Flint model are implemented. Focused GameTests verify the recipe, durability, logs, normal Copper Ore, Tuff, and Stone denial. Natural survival pacing and visuals remain unverified. | +| Reduced Copper generation | Implemented / needs fresh-world verification | Both `minecraft:ore_copper` and `minecraft:ore_copper_large` now make six placement attempts per chunk instead of sixteen, a 62.5% frequency reduction. Vanilla size-10 ordinary and size-20 Dripstone veins plus their height distribution are preserved. A focused registry-backed GameTest verifies both loaded overrides across three seeded origins spanning a chunk border; several fresh seeds, cave-wall exposure, and existing-versus-new chunk behavior still need natural verification. | +| Flint/copper/iron/steel/diamond tool progression | Partial / needs verification | Progression is implemented through Diamond: Wooden/Stone recipes are removed, Copper and Steel geology pacing is active, and unenchanted tagged Diamond tools/Spear use 64 durability while any enchantment restores their vanilla maximum. Removing every enchantment makes them fragile again. Focused tests cover the boundaries and transitions. Netherite/Aenderite equipment and final balance remain incomplete. | +| Campfire, Brick Furnace, Furnace, Blast Furnace, and parallel enchanting progression | Partial / needs verification | Campfires use a fuel-free three-Stick/three-Log recipe. Their initial placement state is unlit on both logical sides, avoiding the former client-visible lit-state flash. Bare Flint ignites one and is consumed in Survival; Flint and Steel retains normal durability use. Campfire cooking fires Clay Balls into Bricks, and eight Bricks craft the Smoker-backed Brick Furnace. The Brick and normal Furnace roles are implemented. Per the 2026-08-11 choice, a standard 100-tick blasting recipe converts one Iron Ingot to one Steel Ingot while accepting ordinary Blast Furnace fuels; Charcoal is valid but not mandatory or fixed 1:1. Blast Furnace construction remains vanilla. Enchanting follows the separate deterministic SGA system. | +| Leather/copper/iron/steel/diamond armor progression | Partial / needs verification | Steel has its provisionally balanced four-piece set. Unenchanted Diamond player armor now uses 6x durability (66/96/90/78), while any enchantment restores vanilla 33x durability and removing all enchantments restores fragility. Horse/Nautilus armor are excluded. Later Retold armor tiers remain incomplete. | +| Diamond tools weak unless enchanted | Implemented / needs in-game verification | A narrow `ItemStack` hook delegates to `RetoldDiamondDurability`; tagged unenchanted tools use 64 durability and enchanted tools use their vanilla maximum. Stripping a heavily damaged item preserves its damage and leaves one final use rather than an invalid stack. Focused coverage verifies tool and armor enchant/remove transitions and the damaged-item edge case. | | Aenderite ore and refined material | Partial / needs verification | Aenderite generates at diamond-like abundance inside Aender Stone, using mostly 3–4 and 4–8 block veins with rare 8–12 block veins, biased toward island undersides. A Netherite Pickaxe is required; Silk Touch preserves the ore, Fortune applies to Raw Aenderite, and raw material smelts/blasts into an ingot. Tools, armor, blocks, and other ingot uses are intentionally not designed yet. | | Enchanting rework | Partial / needs interaction verification | All 43 currently registered enchantments have unique data-driven `domain + effect + modifier` definitions using the fixed 26-concept SGA vocabulary. Duplicate enchantment/word mappings and unknown concepts are rejected atomically, and the validated catalog is synchronized to clients on join and datapack reload. Known enchantment ids persist per player and each receiving client gets its server-authoritative knowledge snapshot. Completed anvil use teaches only book enchantments that actually increased the result compared with the left input. Unknown mapped tooltip entries show only SGA plus level; known entries retain their readable name and add the SGA word. The developer confirmed tooltip behavior and accepted the current table layout in-game on 2026-08-09. The deterministic table transaction, item-aware known-spell filtering, registered maximum display/limits, green success clearing/highlight, and generic low-note/red-highlight rejection cue are implemented with focused coverage. The newest filtering/feedback interaction and dedicated multiplayer synchronization still need verification. | | Iron rods/sticks crafting changes | Not implemented | diff --git a/docs/internal/retold_design_risks.md b/docs/internal/retold_design_risks.md index 43a08f1..1160671 100644 --- a/docs/internal/retold_design_risks.md +++ b/docs/internal/retold_design_risks.md @@ -33,7 +33,7 @@ | Villages | Container, Farmer-crop, and profession-tended livestock offenses use witnessed vanilla gossip. Sight and village-context checks can be sensitive to walls, crowded settlements, vertical farms, merged double chests, animal transport, automation, and multiplayer timing. | Generated village loot plus Villager-produced quantities are protected; player deposits and ambiguous already-opened existing-world contents are not. Farmer planting/replanting marks persistent crop positions. Shepherds, Leatherworkers, and Butchers claim only animals they successfully feed with two real storage items; player interaction/leashing marks previously unowned livestock as player-associated. Offspring of two owned parents inherit persisted village ownership, while an automatic offspring of a player-associated unowned parent inherits player protection. Witnessed direct Survival kills add `-50`; monsters, environment, Creative, and Spectator do not. Four focused animal tests plus the crop/container groups cover persistence, ownership separation, conservation, offense strengths, witnesses, and exclusions; the latest 50-Villager TPS peak is 6.864 ms/tick. Naturally verify physical storage-to-pen routes, wandering/boat-transport edge cases, full harvest/replant cycles, trade prices, golem reaction, double chests, hoppers, simultaneous players, dedicated servers, and existing worlds before calling the loop fully verified. | | Stage 3 | Raid creation is now gated to Stage 3, but the broader illager behavior may need clearer player-facing feedback later. | Avoid major raid redesign without developer approval. The Stage 2 live creation rejection and Witch/Illager same-raid cooperation are regression-tested; natural Bad Omen preservation, Stage 3 Raid Omen conversion, wave participation, healing, and raid-exit behavior still need in-game verification. Existing raids deliberately continue if an administrative command moves the world back below Stage 3. | | Piglins | Stage 3 piglin/pigman hiring or follower behavior is planned but not implemented. | Needs feature design. | -| Items | Tools/armor/ores, enchanting, mending removal, and combat reworks are still planned. | Aenderite provides an ore/raw/ingot foundation but intentionally has no crafting uses. Enchanting now has a fixed 26-concept SGA vocabulary and unique words for all 43 registered enchantments, plus catalog/knowledge persistence and synchronization, completed-anvil learning, knowledge-aware item/book tooltips, and an atomic deterministic server cast transaction. The confirmed cast costs are three lapis plus five experience levels per requested enchantment level. The table screen has three glyph slots, clickable/physical A-Z entry, Backspace, number/keypad levels, Enter-to-Write with duplicate-request prevention, known-word-aware level limits, and a paginated item-aware known-spell panel; vanilla random offers and bookshelf power are disabled. Exact tests cover registry/catalog completeness, payload round trips, known-option filtering/maxima, anvil learning, mixed known/unknown tooltips, cast charging, vanilla conflicts/table eligibility, plain-book conversion, stale menu rejection, and synchronized output/lapis slots. The developer confirmed tooltip behavior, layout, and the current keyboard/table interaction in-game on 2026-08-09. A separate graphical development client successfully connected to a real dedicated server with the enchanting screen mixin loaded; the unrelated missing native narrator library still logs its existing warning. Mending remains mapped only while its planned removal is unimplemented and is rejected by table casting. Simultaneous two-player knowledge isolation and feedback synchronization still need human verification. The wider enchantment audit is also still open. | +| Items | The implemented Flint-through-Diamond spine changes first-spawn assumptions, leaf loot, Copper distribution, Campfire ignition, recipes, station use, mining speed, nine Steel equipment items, and the effective maximum durability of existing Diamond equipment. Its provisional balance, fuel economy, compatibility, and reused visuals need validation. Later equipment, mending removal, and combat reworks remain planned. | Focused GameTests cover the material ladder through Steel, six-attempt ordinary/large Copper placement across seeded chunk-border origins while retaining vanilla vein sizes, the 20% supplemental 1–2 Stick leaf roll and its Fortune/shears/Silk Touch boundaries, the fuel-free Campfire recipe, the real unlit initial placement-state hook, consumable bare-Flint ignition, durable Flint and Steel ignition, Clay-to-Brick campfire cooking, and the eight-Brick furnace boundary, plus dynamic Diamond tool/armor durability, enchant/remove transitions, and the heavily damaged stripped-item edge case. The Copper override affects only newly generated chunks; naturally inspect multiple fresh seeds, ordinary and Dripstone caves, cave-wall exposure, chunk borders, early acquisition time, and datapack/worldgen-mod compatibility before further tuning. Visually verify that Campfire placement no longer flashes lit on the client, plus cooking four Clay items, water/extinguishing, Creative consumption exemption, automation, recipe-book presentation, multiplayer, and compatibility with Campfire/recipe mods. Also verify leaf breaking and decay, explosions, non-Oak and modded tagged leaves, first-spawn Stick pacing, and interaction with datapacks or other global loot modifiers before final tuning. Option 2 means any enchantment grants full vanilla Diamond durability, while removing all enchantments restores fragility; tagged tools/Spear use 64 unenchanted durability and player armor uses 6x. Existing unenchanted Diamond gear changes automatically after update. Naturally test crafting, table/anvil/loot/command enchantments, Grindstone removal, durability bars/tooltips, break timing, repair/Mending interactions, deaths/containers, multiple equipment types, multiplayer, dedicated servers, and existing worlds. A stripped over-cap item deliberately retains one final use. Also measure Steel's ordinary-fuel economy and naturally verify its recipes/stats/repairs/enchanting/trims and reused Iron visuals. Aenderite still provides only an ore/raw/ingot foundation. | | Environment | Death drops should despawn much later than vanilla, not never. | No implementation confirmed. | | Beds | Beds should not skip night; valid daytime bed rest is allowed when night skipping is disabled. | Healing behavior not confirmed implemented. | | Nether | Nether portal spread is planned as energy drain. | Needs bounded implementation design. | diff --git a/docs/internal/retold_mod_system.md b/docs/internal/retold_mod_system.md index 8f9cc4e..23a76ef 100644 --- a/docs/internal/retold_mod_system.md +++ b/docs/internal/retold_mod_system.md @@ -88,6 +88,7 @@ The main event registration is intentionally explicit. When adding a new system, | `mixin` | vanilla behavior hooks and accessors | | `module` | subsystem composition and NeoForge bus registration ownership | | `network` | custom payload registration and handlers | +| `progression` | opening tool harvest rules, Copper-on-Stone pacing, vanilla tool-recipe removal, and focused progression GameTests | | `recipe` | known recipe storage and recipe unlock control | | `registry` | blocks, items, entities, tags, game rules | | `sky` | saved End sky seed data | @@ -120,7 +121,7 @@ split into these modules: | Module | Registration ownership | | --- | --- | -| `RetoldFoundationModule` | blocks, entities, game rules, networking, client bootstrap, commands, player lifecycle, reload listeners, and GameTests | +| `RetoldFoundationModule` | blocks, entities, game rules, networking, client bootstrap, commands, player lifecycle, opening tool progression, reload listeners, and GameTests | | `RetoldStageModule` | stage runtime, End progression, recipe gating, and stage-gated patrols | | `RetoldMobModule` | undead, piglin, golem, enderman, and elder guardian events | | `RetoldWorldgenModule` | worldgen registries, attachments, spawn cache, Air Temple, and delayed structures | @@ -132,6 +133,36 @@ split into these modules: `RetoldSubsystems` registers every mod-bus contribution before game-bus handlers. The module order is dependency-aware: faction precedes territory, and territory precedes behavior. +## Tool And Station Progression + +`RetoldToolProgressionEvents` owns the non-data opening rules: logs require a correct held tool, +the Copper Pickaxe receives a Stone-specific speed penalty, Copper and Iron Pickaxes receive the +Steel-tier Deepslate penalty, and exact vanilla Wooden/Stone tool recipes are removed during recipe +JSON modification. `RetoldLeafStickLootModifier`, registered through `RetoldLootModifiers`, gives +every `minecraft:leaves` block a supplemental 20% roll for 1–2 Sticks, increasing five percentage +points per Fortune level and excluding shears and Silk Touch. `RetoldBlocks` registers the Flint +Multi-tool and provisional Steel tool/armor materials, while block/item tags own mining, repair, +enchantment-family, and equipment boundaries. Vanilla placed-feature overrides reduce ordinary +and Dripstone Copper from sixteen to six attempts per chunk while retaining vanilla vein sizes and +height distribution; only newly generated chunks receive the reduced distribution. +`CampfirePlacementMixin` is a narrow initial-state hook that delegates to +`RetoldCampfireProgressionEvents`, making Campfires unlit on both logical sides before placement can +render. The event class owns consumable bare-Flint ignition, while vanilla Flint and Steel remains +the durable alternative. Recipes remove Coal from +the three-Stick/three-Log Campfire, fire Clay Balls into Bricks through campfire cooking, repurpose +the vanilla Smoker as the eight-Brick Brick Furnace, add its Copper/Charcoal processing, blast Iron +Ingots directly into Steel, and craft the full standard Steel tool and armor sets. These rules are +server-owned; client resources provide names and deliberately reference vanilla Flint/Iron models +until final art is approved. + +`RetoldDiamondDurability` owns the selected dynamic Diamond rule. `ItemStackDiamondDurabilityMixin` +is only the return-value hook for `ItemStack.getMaxDamage`; separate item tags identify affected +Diamond tools/Spear and player armor. Unenchanted tools use 64 durability and armor scales from +vanilla's 33x to 6x. Any enchantment restores the underlying vanilla maximum, while removing all +enchantments restores fragility. Raw damage is read directly from the component so the hook cannot +re-enter itself; an over-cap stripped item receives an effective `damage + 1` maximum and one final +use. + ## World Stage System World stages are the backbone of Retold progression. diff --git a/docs/internal/retold_roadmap.md b/docs/internal/retold_roadmap.md index c19c6b8..4b7f11c 100644 --- a/docs/internal/retold_roadmap.md +++ b/docs/internal/retold_roadmap.md @@ -39,7 +39,7 @@ These are the strongest next design-aligned areas: These are still planned but need feature-specific design before implementation: -- full tools, armor, ores, and station progression rework beyond the initial Aenderite material foundation +- tool, armor, ore, and station progression beyond the implemented Flint-through-Diamond spine, six-attempt-per-chunk Copper frequency adjustment, and initial Aenderite material foundation; next naturally verify Copper density and the dynamic Diamond rule, then design remaining Netherite/Aenderite equipment boundaries - enchanting rework beyond the implemented complete 43-spell SGA catalog, knowledge persistence/sync, anvil-learning route, knowledge-aware tooltips, and deterministic glyph-entry table; next verify/refine the composed client layout and dedicated multiplayer synchronization, then perform the wider enchantment audit - mending removal - sword/shield combat rework diff --git a/docs/internal/tool_armor_ore_progression.md b/docs/internal/tool_armor_ore_progression.md index b3547dd..9f5356e 100644 --- a/docs/internal/tool_armor_ore_progression.md +++ b/docs/internal/tool_armor_ore_progression.md @@ -1,6 +1,6 @@ # Tool, Armor, Ore, And Station Progression -> Developer-confirmed design direction from the 2026-08-10 progression pass. This document supersedes the older first-draft progression table where the two conflict. Exact mining speeds, durability, combat stats, ore frequencies, Steel ratios, Aenderite abilities, and Gold's role remain future balancing/design work. +> Developer-confirmed design direction from the 2026-08-10 progression pass, updated by the 2026-08-11 Steel-production choice. This document supersedes the older first-draft progression table where the two conflict. Final mining speeds, durability, combat stats, ore frequencies, Aenderite abilities, and Gold's role remain future balancing/design work. ## Core Progression @@ -35,7 +35,11 @@ primitive surface resources -> Aender resources ``` -Keep vanilla ore generation by default. The progression changes what geology the player can practically mine and therefore rewards caves, exposed ore, and terrain reading without requiring a separate Retold ore-generation ladder. +Keep vanilla ore generation by default except where natural playtesting identifies a concrete +problem. Copper is the first confirmed exception: its placement frequency is reduced while its +vein size, height distribution, and biome identities remain vanilla. The progression otherwise +changes what geology the player can practically mine and therefore rewards caves, exposed ore, +and terrain reading without requiring a separate Retold ore-generation ladder. ## Stations @@ -47,9 +51,9 @@ Retold keeps the station vocabulary simple and recognizable. - crafted from planks as in vanilla - cannot be the first required recipe because the player initially cannot obtain wood by hand -### Clay Furnace +### Brick Furnace -The Clay Furnace replaces the gameplay role of the vanilla **Smoker**. +The Brick Furnace replaces the gameplay role of the vanilla **Smoker**. It is the early cooking station and also performs the one progression-critical metal process needed before a normal Furnace is available: @@ -58,7 +62,30 @@ It is the early cooking station and also performs the one progression-critical m - **smelts Copper ore into Copper** - does not replace the normal Furnace for later ordinary ore smelting -The exact Clay Furnace crafting recipe is still to be finalized, but it must be obtainable before normal Stone/Cobblestone access. +The player must first fire Clay Balls into Bricks on a Campfire. A Campfire is crafted without a +fuel item from three Sticks and three Logs: + +```text + Stick +Stick Stick +Log Log Log +``` + +Newly placed Campfires begin unlit. A bare Flint lights an unlit, non-waterlogged Campfire and is +consumed in Survival; Flint and Steel also works through its ordinary durability-based behavior. +Campfire cooking turns one Clay Ball into one Brick in 600 ticks. Eight fired Bricks in a ring then +craft the Brick Furnace: + +```text +Brick Brick Brick +Brick - Brick +Brick Brick Brick +``` + +The Brick Furnace reuses the vanilla Smoker block and recipe identity. Its English block and +container name is replaced with **Brick Furnace**. The current implementation +keeps the vanilla Smoker model as a provisional visual and adds smoking recipes for burnable logs, +Raw Copper, Copper Ore, and Deepslate Copper Ore. Food retains the Smoker's normal recipe support. ### Furnace @@ -75,10 +102,16 @@ The Blast Furnace remains the advanced metalworking station. Its key Retold progression role is Steel production: ```text -Iron + Charcoal -> Steel +Iron Ingot +-> Blast Furnace using ordinary fuel +-> Steel Ingot ``` -Iron and Charcoal are both consumed as part of Steel production; exact item ratios and final recipe representation remain balancing work. +The developer chose normal blasting on 2026-08-11. Iron Ingots are the recipe input and Steel +Ingots are the output at the normal 100-tick blasting duration. Charcoal works as ordinary fuel, +but the recipe does not require it specifically or consume it at a fixed 1:1 ratio; all fuels that +normally power a Blast Furnace remain valid. This intentionally accepts vanilla's fuel efficiency +instead of adding custom fuel-slot logic. Blast Furnace construction should broadly preserve the old Retold direction of requiring advanced masonry/metal materials such as bricks and iron, while staying visually/readably close to normal Minecraft crafting. Exact recipe remains to be finalized. @@ -105,6 +138,12 @@ The player begins by gathering materials that do not require tools: - break leaves to obtain Sticks - break Gravel to obtain Flint +All blocks in the standard `minecraft:leaves` tag receive a supplemental 20% chance to drop 1–2 +Sticks. Fortune adds five percentage points per level (25%/30%/35% for Fortune I/II/III). This is +independent of the leaf's ordinary loot-table Stick roll, so the vanilla drop remains possible too. +Shears and Silk Touch do not receive the supplemental drop and continue harvesting the leaf block +normally. The values are provisional until the natural opening loop is playtested. + The first essential tool is the **Flint Multi-tool**. ### Flint Multi-tool recipe @@ -138,6 +177,12 @@ Its key purposes are: It is not a full conventional tool set. Flint remains a deliberately primitive stage. +The first implemented balance uses 48 durability, mining speed 2.0, attack damage 1.0, and attack +speed -2.8. Its data-driven mining list combines normal axe and shovel blocks with ordinary Copper +Ore, Sandstone variants, Tuff, and Calcite. It cannot harvest normal Stone, Deepslate Copper Ore, +or blocks that require Iron or Diamond. These values and the exact soft-block list are provisional +until the natural opening loop is playtested. + Once the player can obtain logs: ```text @@ -153,13 +198,18 @@ Copper is the first proper metal and the first conventional equipment tier. ### Obtaining Copper -Retold should initially keep vanilla Copper ore generation. Early Copper therefore comes primarily from naturally exposed/accessible deposits in caves, cliffs, terrain cuts, and other places the Flint Multi-tool can reach. +Following developer cave-play feedback on 2026-08-11, both ordinary and Dripstone Copper placed +features make six attempts per chunk instead of vanilla's sixteen. Ordinary veins retain size 10 +and Dripstone Cave veins retain size 20, along with the vanilla -16-to-112 triangular height +distribution. Early Copper therefore still comes primarily from naturally exposed deposits in +caves, cliffs, terrain cuts, and other places the Flint Multi-tool can reach, but it should no +longer cover cave walls continuously. -Copper ore is processed in the **Clay Furnace**. +Copper ore is processed in the **Brick Furnace**. ```text accessible Copper ore --> Clay Furnace +-> Brick Furnace -> Copper ingots ``` @@ -182,7 +232,9 @@ The important behavior is: Copper also handles the softer early stone-like materials from the original draft, including things such as Tuff and Sandstone. The old placeholder phrase "very hardly stone" refers to this broad soft/weak stone-like category and should not be interpreted as "very hard stone." -The exact tag/block list should be decided during implementation. +The first implemented balance applies 25% of the Copper Pickaxe's otherwise calculated mining +speed specifically to normal Stone. Other Copper mining behavior remains vanilla until the later +tier-wide balance pass. ### Copper-to-Iron loop @@ -191,7 +243,7 @@ The intended early loop is: ```text Flint Multi-tool -> exposed Copper --> Clay Furnace +-> Brick Furnace -> Copper ingots -> Copper Pickaxe -> slowly mine Stone for Cobblestone @@ -232,17 +284,19 @@ Steel is an engineered material rather than a naturally mined ore. ### Production -Confirmed conceptual recipe: +Implemented production: ```text -Iron + Charcoal +Iron Ingot -> Blast Furnace --> Steel +-> Steel Ingot ``` Steel therefore represents infrastructure and processing rather than simply finding a rarer rock. -Exact material ratios, processing duration, and fuel behavior are future implementation/balance work. +The recipe uses normal blasting at 100 ticks. Charcoal is an ordinary valid fuel rather than a +second recipe ingredient, so other vanilla Blast Furnace fuels also work and each fuel processes +its normal number of items. ### Steel equipment @@ -250,10 +304,24 @@ Steel receives a full normal tool and armor set. It should be the strongest conventional Overworld workhorse material before Diamond becomes a magical progression step. +The provisional tool material uses 750 durability, mining speed 7.0, attack bonus 2.5, and +enchantability 12. The implemented set contains Pickaxe, Axe, Shovel, Hoe, and Sword; nonstandard +weapons such as the Spear remain part of the later combat/tool audit. + +The provisional armor material uses durability multiplier 25, enchantability 12, toughness 1, +and defenses of 3 Helmet, 7 Chestplate, 6 Leggings, and 3 Boots. Until a Steel art direction is +approved, inventory and equipped models deliberately reference vanilla Iron visuals without +copying or modifying Minecraft textures. + ### Steel mining identity Steel is the tier that makes **Deepslate** practically mineable and opens the deepest Overworld geology. +Copper and Iron Pickaxes can still harvest applicable Deepslate-family blocks, but do so at 25% +of their otherwise calculated speed. The data-driven Steel-tier list contains natural Deepslate, +its construction variants, and Deepslate ores. Steel mines them at its full speed, can harvest +Deepslate Diamond Ore, and still cannot harvest Obsidian, preserving Diamond's next access step. + This naturally gates practical Diamond access behind Steel because modern vanilla Diamond generation strongly favors deep/deepslate regions. Keep vanilla Diamond generation initially; let geological access provide the progression gate. @@ -277,11 +345,26 @@ Steel Diamond tools and armor can be crafted normally, but **unenchanted Diamond equipment has very low durability**. +The developer chose dynamic durability on 2026-08-11: + +- unenchanted Diamond Sword, Shovel, Pickaxe, Axe, Hoe, and Spear have 64 maximum durability +- unenchanted Diamond player armor uses durability multiplier 6: Helmet 66, Chestplate 96, + Leggings 90, and Boots 78 +- while any enchantment is present, the item immediately uses its full vanilla Diamond durability +- removing every enchantment, including through a Grindstone, immediately restores the fragile + maximum +- if the preserved damage value already exceeds that fragile maximum, the effective maximum is + temporarily `damage + 1`, leaving one final use instead of creating an already-broken stack +- re-enchanting the item restores the full maximum again without changing its preserved damage + +This rule is data-driven through separate Retold Diamond tool and player-armor tags. Horse and +Nautilus armor are not included. + The intended relationship is: - Steel = excellent reliable conventional equipment - unenchanted Diamond = powerful material used incorrectly / impractical -- enchanted Diamond = proper high-end magical equipment +- enchanted Diamond = proper high-end magical equipment with full vanilla durability The implemented SGA enchanting system provides the knowledge/energy layer for this progression. @@ -337,7 +420,7 @@ Flint Multi-tool -> Crafting Table Find accessible/exposed Copper --> Clay Furnace +-> Brick Furnace -> Copper ingots -> Copper tools/armor @@ -352,9 +435,9 @@ Find Iron -> Iron tools/armor -> normal Stone mining becomes practical -Iron + Charcoal +Iron Ingot + ordinary Blast Furnace fuel -> Blast Furnace --> Steel +-> Steel Ingot -> Steel tools/armor -> Deepslate becomes practical @@ -412,11 +495,14 @@ Netherite upgrades Diamond gear. Aenderite armor behavior remains TBD and should be designed around Aender-specific utility rather than only defense inflation. -## Vanilla World Generation +## Overworld Ore Generation -Default direction is to retain vanilla Overworld ore generation initially. +Default direction is to retain vanilla Overworld ore generation until playtesting identifies a +specific problem. The confirmed Copper-density complaint is the first such adjustment. -Do not redesign Copper/Iron/Diamond generation pre-emptively merely to enforce the tool ladder. +Ordinary and large Copper placed features use six attempts per chunk instead of sixteen. Their +configured vein sizes and height range remain unchanged. Iron and Diamond generation remain +vanilla; do not redesign them pre-emptively merely to enforce the tool ladder. The intended experience is that early players rely more heavily on: @@ -425,35 +511,38 @@ The intended experience is that early players rely more heavily on: - cliffs and terrain cuts - naturally accessible geology -Playtest the progression first. Only adjust ore exposure/frequency if normal seeds repeatedly create frustrating or effectively blocked progression. +Continue testing fresh seeds, cave exposure, and chunk borders. Tune the provisional six-attempt +Copper rate again only from concrete natural-world results. ## Confirmed Guardrails - Wood logs cannot be harvested by hand at the start. - The Flint Multi-tool is the primitive combined axe/shovel/pick-like starter tool. - The Flint Multi-tool recipe is exactly two Flint across the top and one Stick below the right-hand Flint in the 2x2 inventory grid. -- Clay Furnace fills the Smoker role and smelts Copper. +- Vanilla Wooden and Stone axe, hoe, pickaxe, shovel, spear, and sword recipes are removed so they cannot bypass Copper progression. +- Campfires use three Sticks and three Logs without Coal or Flint, begin unlit, and can be lit by consuming bare Flint or by using Flint and Steel durability. +- Campfire cooking fires Clay Balls into Bricks. +- Brick Furnace fills the Smoker role, smelts Copper, and is crafted from eight Bricks in a ring. - Furnace remains the normal Furnace and smelts Iron/ordinary furnace recipes. - Copper Pickaxe can mine Stone and obtain Cobblestone, but does so slowly. - Iron makes Stone mining practical. -- Steel is produced from Iron + Charcoal in the Blast Furnace. +- Steel is produced by blasting Iron Ingots; Charcoal is an ordinary valid fuel rather than a required second ingredient. - Steel makes Deepslate practical and thereby opens deep Diamond progression. - Copper and Steel receive full tool and armor sets. - Standard tool families follow the same tier ladder from Copper onward. - Diamond equipment has very low durability until enchanted. +- Diamond durability is dynamic: removing every enchantment makes tagged Diamond tools and player armor fragile again. - Netherite sits between Diamond and Aenderite and upgrades Diamond equipment. - Aenderite is the final exotic tier but must have an identity beyond bigger stats. -- Keep vanilla ore generation initially and adjust only if playtesting demonstrates a concrete progression problem. +- Keep vanilla Iron and Diamond generation; Copper is the confirmed exception at six vein attempts per chunk with vanilla vein sizes. - Gold is intentionally deferred to a separate design pass. ## Still Undecided -- exact Clay Furnace crafting recipe - exact Blast Furnace crafting recipe if Retold changes vanilla's recipe -- exact Iron + Charcoal -> Steel ratios and processing details -- exact tool mining speeds and durability per tier -- exact armor/combat stats -- exact block/tag harvest lists for Flint, Copper, Iron, Steel, Diamond, Netherite, and Aenderite +- final tool mining speeds and durability per tier beyond the provisional Flint, Copper, Steel, and unenchanted Diamond values +- final armor/combat stats beyond the provisional Steel and unenchanted Diamond values +- exact block/tag harvest lists beyond the implemented Flint and Steel-tier opening boundaries - exact handling of Ancient Debris harvest level - exact role and progression position of Gold - whether Smithing Table remains or Netherite upgrade functionality moves into the Anvil diff --git a/src/main/java/cz/xefensor/retold/gametest/RetoldGameTests.java b/src/main/java/cz/xefensor/retold/gametest/RetoldGameTests.java index 6c5b647..a6fb819 100644 --- a/src/main/java/cz/xefensor/retold/gametest/RetoldGameTests.java +++ b/src/main/java/cz/xefensor/retold/gametest/RetoldGameTests.java @@ -49,6 +49,7 @@ import cz.xefensor.retold.event.RetoldPlayerSyncEvents; import cz.xefensor.retold.event.RetoldSnowballGameTests; import cz.xefensor.retold.event.RetoldVexGameTests; +import cz.xefensor.retold.progression.RetoldToolProgressionGameTests; import cz.xefensor.retold.registry.RetoldBlocks; import cz.xefensor.retold.stage.RetoldElementType; import cz.xefensor.retold.stage.RetoldRaidProgression; @@ -258,6 +259,7 @@ public static void register(RegisterGameTestsEvent event) { RetoldVexGameTests.register(event, environment); RetoldSnowballGameTests.register(event, environment); RetoldEnchantingGameTests.register(event, environment); + RetoldToolProgressionGameTests.register(event, environment); RetoldTerritoryGameTests.register(event, environment); RetoldVillagerCommunalFoodGameTests.register(event); RetoldVillagerGolemConstructionGameTests.register(event); diff --git a/src/main/java/cz/xefensor/retold/mixin/CampfirePlacementMixin.java b/src/main/java/cz/xefensor/retold/mixin/CampfirePlacementMixin.java new file mode 100644 index 0000000..23d2e37 --- /dev/null +++ b/src/main/java/cz/xefensor/retold/mixin/CampfirePlacementMixin.java @@ -0,0 +1,28 @@ +package cz.xefensor.retold.mixin; + +import cz.xefensor.retold.progression.RetoldCampfireProgressionEvents; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.block.CampfireBlock; +import net.minecraft.world.level.block.state.BlockState; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(CampfireBlock.class) +public abstract class CampfirePlacementMixin { + @Inject(method = "getStateForPlacement", at = @At("RETURN"), cancellable = true) + private void retold$placeCampfiresUnlit( + BlockPlaceContext context, + CallbackInfoReturnable callbackInfo + ) { + BlockState placementState = callbackInfo.getReturnValue(); + if (placementState != null) { + callbackInfo.setReturnValue( + RetoldCampfireProgressionEvents.unlitPlacementState( + placementState + ) + ); + } + } +} diff --git a/src/main/java/cz/xefensor/retold/mixin/ItemStackDiamondDurabilityMixin.java b/src/main/java/cz/xefensor/retold/mixin/ItemStackDiamondDurabilityMixin.java new file mode 100644 index 0000000..c60674f --- /dev/null +++ b/src/main/java/cz/xefensor/retold/mixin/ItemStackDiamondDurabilityMixin.java @@ -0,0 +1,24 @@ +package cz.xefensor.retold.mixin; + +import cz.xefensor.retold.progression.RetoldDiamondDurability; +import net.minecraft.world.item.ItemStack; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(ItemStack.class) +public abstract class ItemStackDiamondDurabilityMixin { + @Inject(method = "getMaxDamage", at = @At("RETURN"), cancellable = true) + private void retold$applyDynamicDiamondDurability( + CallbackInfoReturnable callbackInfo + ) { + ItemStack stack = (ItemStack) (Object) this; + callbackInfo.setReturnValue( + RetoldDiamondDurability.effectiveMaxDamage( + stack, + callbackInfo.getReturnValue() + ) + ); + } +} diff --git a/src/main/java/cz/xefensor/retold/module/RetoldFoundationModule.java b/src/main/java/cz/xefensor/retold/module/RetoldFoundationModule.java index 52bf2b6..41d95e9 100644 --- a/src/main/java/cz/xefensor/retold/module/RetoldFoundationModule.java +++ b/src/main/java/cz/xefensor/retold/module/RetoldFoundationModule.java @@ -10,6 +10,9 @@ import cz.xefensor.retold.event.TorchWeatherEvents; import cz.xefensor.retold.gametest.RetoldGameTests; import cz.xefensor.retold.network.RetoldNetworking; +import cz.xefensor.retold.progression.RetoldCampfireProgressionEvents; +import cz.xefensor.retold.progression.RetoldLootModifiers; +import cz.xefensor.retold.progression.RetoldToolProgressionEvents; import cz.xefensor.retold.registry.RetoldBlocks; import cz.xefensor.retold.registry.RetoldBlockEntities; import cz.xefensor.retold.registry.RetoldEntityEvents; @@ -27,6 +30,7 @@ private RetoldFoundationModule() { public static void registerModBus(IEventBus modEventBus) { RetoldBlocks.register(modEventBus); + RetoldLootModifiers.register(modEventBus); RetoldBlockEntities.register(modEventBus); RetoldEntityTypes.register(modEventBus); RetoldGameRules.register(modEventBus); @@ -47,6 +51,8 @@ public static void registerGameBus(IEventBus gameEventBus) { gameEventBus.register(RetoldCommandEvents.class); gameEventBus.register(RetoldPlayerSyncEvents.class); gameEventBus.register(RetoldSleepEvents.class); + gameEventBus.register(RetoldCampfireProgressionEvents.class); + gameEventBus.register(RetoldToolProgressionEvents.class); gameEventBus.register(TorchWeatherEvents.class); gameEventBus.addListener(RetoldFoundationModule::addServerReloadListeners); } diff --git a/src/main/java/cz/xefensor/retold/progression/RetoldCampfireProgressionEvents.java b/src/main/java/cz/xefensor/retold/progression/RetoldCampfireProgressionEvents.java new file mode 100644 index 0000000..b53cc5a --- /dev/null +++ b/src/main/java/cz/xefensor/retold/progression/RetoldCampfireProgressionEvents.java @@ -0,0 +1,88 @@ +package cz.xefensor.retold.progression; + +import net.minecraft.core.BlockPos; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.stats.Stats; +import net.minecraft.tags.BlockTags; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.CampfireBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.gameevent.GameEvent; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.neoforge.event.entity.player.PlayerInteractEvent; + +public final class RetoldCampfireProgressionEvents { + private RetoldCampfireProgressionEvents() { + } + + @SubscribeEvent + public static void onFlintUsedOnCampfire( + PlayerInteractEvent.RightClickBlock event + ) { + if (!lightWithFlint( + event.getLevel(), + event.getPos(), + event.getEntity(), + event.getItemStack() + )) { + return; + } + + event.setCancellationResult(InteractionResult.SUCCESS); + event.setCanceled(true); + } + + public static BlockState unlitPlacementState(BlockState state) { + if (!state.is(BlockTags.CAMPFIRES) + || !state.hasProperty(CampfireBlock.LIT) + || !state.getValue(CampfireBlock.LIT)) { + return state; + } + + return state.setValue(CampfireBlock.LIT, false); + } + + static boolean lightWithFlint( + Level level, + BlockPos pos, + Player player, + ItemStack stack + ) { + BlockState state = level.getBlockState(pos); + if (!stack.is(Items.FLINT) || !CampfireBlock.canLight(state)) { + return false; + } + + if (level.isClientSide()) { + return true; + } + + level.setBlock( + pos, + state.setValue(CampfireBlock.LIT, true), + Block.UPDATE_ALL + ); + level.playSound( + null, + pos, + SoundEvents.FLINTANDSTEEL_USE, + SoundSource.BLOCKS, + 1.0F, + level.getRandom().nextFloat() * 0.4F + 0.8F + ); + level.gameEvent(player, GameEvent.BLOCK_CHANGE, pos); + player.awardStat(Stats.ITEM_USED.get(Items.FLINT)); + + if (!player.getAbilities().instabuild) { + stack.shrink(1); + } + + return true; + } +} diff --git a/src/main/java/cz/xefensor/retold/progression/RetoldDiamondDurability.java b/src/main/java/cz/xefensor/retold/progression/RetoldDiamondDurability.java new file mode 100644 index 0000000..902684b --- /dev/null +++ b/src/main/java/cz/xefensor/retold/progression/RetoldDiamondDurability.java @@ -0,0 +1,47 @@ +package cz.xefensor.retold.progression; + +import cz.xefensor.retold.registry.RetoldTags; +import net.minecraft.core.component.DataComponents; +import net.minecraft.world.item.ItemStack; + +public final class RetoldDiamondDurability { + public static final int UNENCHANTED_TOOL_DURABILITY = 64; + private static final int ARMOR_DURABILITY_NUMERATOR = 6; + private static final int VANILLA_DIAMOND_ARMOR_DURABILITY = 33; + + private RetoldDiamondDurability() { + } + + public static int effectiveMaxDamage( + ItemStack stack, + int baseMaxDamage + ) { + if (baseMaxDamage <= 0 || stack.isEnchanted()) { + return baseMaxDamage; + } + + int fragileMaxDamage; + if (stack.is(RetoldTags.FRAGILE_UNENCHANTED_DIAMOND_TOOLS)) { + fragileMaxDamage = UNENCHANTED_TOOL_DURABILITY; + } else if (stack.is( + RetoldTags.FRAGILE_UNENCHANTED_DIAMOND_ARMOR + )) { + fragileMaxDamage = Math.max( + 1, + baseMaxDamage * ARMOR_DURABILITY_NUMERATOR + / VANILLA_DIAMOND_ARMOR_DURABILITY + ); + } else { + return baseMaxDamage; + } + + int minimumValidMaxDamage = Math.min( + baseMaxDamage, + stack.getOrDefault(DataComponents.DAMAGE, 0) + 1 + ); + return Math.min( + baseMaxDamage, + Math.max(fragileMaxDamage, minimumValidMaxDamage) + ); + } +} diff --git a/src/main/java/cz/xefensor/retold/progression/RetoldLeafStickLootModifier.java b/src/main/java/cz/xefensor/retold/progression/RetoldLeafStickLootModifier.java new file mode 100644 index 0000000..ea14942 --- /dev/null +++ b/src/main/java/cz/xefensor/retold/progression/RetoldLeafStickLootModifier.java @@ -0,0 +1,89 @@ +package cz.xefensor.retold.progression; + +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import net.minecraft.core.registries.Registries; +import net.minecraft.tags.BlockTags; +import net.minecraft.world.item.ItemInstance; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.enchantment.Enchantments; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.storage.loot.LootContext; +import net.minecraft.world.level.storage.loot.parameters.LootContextParams; +import net.minecraft.world.level.storage.loot.predicates.LootItemCondition; +import net.neoforged.neoforge.common.loot.IGlobalLootModifier; +import net.neoforged.neoforge.common.loot.LootModifier; + +/** + * Adds a reliable early-game Stick source to all blocks in the vanilla leaves + * tag while preserving the normal shears and Silk Touch harvest paths. + */ +public final class RetoldLeafStickLootModifier extends LootModifier { + static final float BASE_CHANCE = 0.20F; + static final float FORTUNE_CHANCE_PER_LEVEL = 0.05F; + + public static final MapCodec CODEC = + RecordCodecBuilder.mapCodec(instance -> codecStart(instance).apply( + instance, + RetoldLeafStickLootModifier::new + )); + + public RetoldLeafStickLootModifier( + LootItemCondition[] conditions, + int priority + ) { + super(conditions, priority); + } + + @Override + protected ObjectArrayList doApply( + ObjectArrayList generatedLoot, + LootContext context + ) { + BlockState state = context.getOptionalParameter( + LootContextParams.BLOCK_STATE + ); + ItemInstance tool = context.getOptionalParameter(LootContextParams.TOOL); + if (state == null || tool == null || !state.is(BlockTags.LEAVES)) { + return generatedLoot; + } + + var enchantments = context.getLevel() + .registryAccess() + .lookupOrThrow(Registries.ENCHANTMENT); + int silkTouchLevel = tool.getEnchantmentLevel( + enchantments.getOrThrow(Enchantments.SILK_TOUCH) + ); + if (tool.is(Items.SHEARS) || silkTouchLevel > 0) { + return generatedLoot; + } + + int fortuneLevel = tool.getEnchantmentLevel( + enchantments.getOrThrow(Enchantments.FORTUNE) + ); + if (context.getRandom().nextFloat() < chanceForFortune(fortuneLevel)) { + generatedLoot.add(new ItemStack( + Items.STICK, + 1 + context.getRandom().nextInt(2) + )); + } + + return generatedLoot; + } + + static float chanceForFortune(int fortuneLevel) { + return Math.min( + 1.0F, + BASE_CHANCE + + Math.max(0, fortuneLevel) + * FORTUNE_CHANCE_PER_LEVEL + ); + } + + @Override + public MapCodec codec() { + return RetoldLootModifiers.MORE_LEAF_STICKS.get(); + } +} diff --git a/src/main/java/cz/xefensor/retold/progression/RetoldLootModifiers.java b/src/main/java/cz/xefensor/retold/progression/RetoldLootModifiers.java new file mode 100644 index 0000000..dc46abc --- /dev/null +++ b/src/main/java/cz/xefensor/retold/progression/RetoldLootModifiers.java @@ -0,0 +1,33 @@ +package cz.xefensor.retold.progression; + +import com.mojang.serialization.MapCodec; +import cz.xefensor.retold.Retold; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.neoforge.common.loot.IGlobalLootModifier; +import net.neoforged.neoforge.registries.DeferredHolder; +import net.neoforged.neoforge.registries.DeferredRegister; +import net.neoforged.neoforge.registries.NeoForgeRegistries; + +public final class RetoldLootModifiers { + private static final DeferredRegister< + MapCodec + > SERIALIZERS = DeferredRegister.create( + NeoForgeRegistries.Keys.GLOBAL_LOOT_MODIFIER_SERIALIZERS, + Retold.MODID + ); + + public static final DeferredHolder< + MapCodec, + MapCodec + > MORE_LEAF_STICKS = SERIALIZERS.register( + "more_leaf_sticks", + () -> RetoldLeafStickLootModifier.CODEC + ); + + private RetoldLootModifiers() { + } + + public static void register(IEventBus modEventBus) { + SERIALIZERS.register(modEventBus); + } +} diff --git a/src/main/java/cz/xefensor/retold/progression/RetoldToolProgressionEvents.java b/src/main/java/cz/xefensor/retold/progression/RetoldToolProgressionEvents.java new file mode 100644 index 0000000..1ff9c1a --- /dev/null +++ b/src/main/java/cz/xefensor/retold/progression/RetoldToolProgressionEvents.java @@ -0,0 +1,90 @@ +package cz.xefensor.retold.progression; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import cz.xefensor.retold.registry.RetoldTags; +import net.minecraft.resources.Identifier; +import net.minecraft.tags.BlockTags; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.level.block.Blocks; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.neoforge.event.ModifyRecipeJsonsEvent; +import net.neoforged.neoforge.event.entity.player.PlayerEvent; + +import java.util.Set; + +public final class RetoldToolProgressionEvents { + private static final float COPPER_STONE_SPEED_MULTIPLIER = 0.25F; + private static final float PRE_STEEL_DEEPSLATE_SPEED_MULTIPLIER = 0.25F; + private static final Identifier CAMPFIRE_RECIPE = + Identifier.withDefaultNamespace("campfire"); + private static final Set DISABLED_TOOL_RECIPES = Set.of( + Identifier.withDefaultNamespace("wooden_axe"), + Identifier.withDefaultNamespace("wooden_hoe"), + Identifier.withDefaultNamespace("wooden_pickaxe"), + Identifier.withDefaultNamespace("wooden_shovel"), + Identifier.withDefaultNamespace("wooden_spear"), + Identifier.withDefaultNamespace("wooden_sword"), + Identifier.withDefaultNamespace("stone_axe"), + Identifier.withDefaultNamespace("stone_hoe"), + Identifier.withDefaultNamespace("stone_pickaxe"), + Identifier.withDefaultNamespace("stone_shovel"), + Identifier.withDefaultNamespace("stone_spear"), + Identifier.withDefaultNamespace("stone_sword") + ); + + private RetoldToolProgressionEvents() { + } + + @SubscribeEvent + public static void onModifyRecipeJsons(ModifyRecipeJsonsEvent event) { + event.getRecipeJsons().keySet().removeAll(DISABLED_TOOL_RECIPES); + + JsonObject campfireRecipe = event.getRecipeJsons() + .get(CAMPFIRE_RECIPE) + .getAsJsonObject(); + JsonObject ingredients = new JsonObject(); + ingredients.addProperty("L", "#minecraft:logs"); + ingredients.addProperty("S", "minecraft:stick"); + campfireRecipe.add("key", ingredients); + + JsonArray pattern = new JsonArray(); + pattern.add(" S "); + pattern.add("S S"); + pattern.add("LLL"); + campfireRecipe.add("pattern", pattern); + } + + @SubscribeEvent + public static void onHarvestCheck(PlayerEvent.HarvestCheck event) { + if (!event.getTargetBlock().is(BlockTags.LOGS)) { + return; + } + + ItemStack tool = event.getEntity().getMainHandItem(); + event.setCanHarvest(tool.isCorrectToolForDrops(event.getTargetBlock())); + } + + @SubscribeEvent + public static void onBreakSpeed(PlayerEvent.BreakSpeed event) { + if (event.isCanceled()) { + return; + } + + ItemStack tool = event.getEntity().getMainHandItem(); + if (tool.is(Items.COPPER_PICKAXE) + && event.getState().is(Blocks.STONE)) { + event.setNewSpeed( + event.getNewSpeed() * COPPER_STONE_SPEED_MULTIPLIER + ); + } else if ((tool.is(Items.COPPER_PICKAXE) + || tool.is(Items.IRON_PICKAXE)) + && event.getState().is(RetoldTags.STEEL_TIER_BLOCKS)) { + event.setNewSpeed( + event.getNewSpeed() + * PRE_STEEL_DEEPSLATE_SPEED_MULTIPLIER + ); + } + } +} diff --git a/src/main/java/cz/xefensor/retold/progression/RetoldToolProgressionGameTests.java b/src/main/java/cz/xefensor/retold/progression/RetoldToolProgressionGameTests.java new file mode 100644 index 0000000..9f45fd8 --- /dev/null +++ b/src/main/java/cz/xefensor/retold/progression/RetoldToolProgressionGameTests.java @@ -0,0 +1,949 @@ +package cz.xefensor.retold.progression; + +import cz.xefensor.retold.registry.RetoldBlocks; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Holder; +import net.minecraft.core.component.DataComponents; +import net.minecraft.core.registries.Registries; +import net.minecraft.gametest.framework.BuiltinTestFunctions; +import net.minecraft.gametest.framework.FunctionGameTestInstance; +import net.minecraft.gametest.framework.GameTestHelper; +import net.minecraft.gametest.framework.TestData; +import net.minecraft.gametest.framework.TestEnvironmentDefinition; +import net.minecraft.resources.Identifier; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.tags.ItemTags; +import net.minecraft.util.RandomSource; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.crafting.BlastingRecipe; +import net.minecraft.world.item.crafting.CampfireCookingRecipe; +import net.minecraft.world.item.crafting.CraftingInput; +import net.minecraft.world.item.crafting.CraftingRecipe; +import net.minecraft.world.item.crafting.Recipe; +import net.minecraft.world.item.crafting.RecipeHolder; +import net.minecraft.world.item.crafting.RecipeManager; +import net.minecraft.world.item.crafting.RecipeType; +import net.minecraft.world.item.crafting.SingleRecipeInput; +import net.minecraft.world.item.crafting.SmokingRecipe; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.item.enchantment.Enchantments; +import net.minecraft.world.item.enchantment.ItemEnchantments; +import net.minecraft.world.level.GameType; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.CampfireBlock; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.storage.loot.LootParams; +import net.minecraft.world.level.storage.loot.LootTable; +import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets; +import net.minecraft.world.level.storage.loot.parameters.LootContextParams; +import net.minecraft.world.level.levelgen.feature.configurations.OreConfiguration; +import net.minecraft.world.level.levelgen.placement.CountPlacement; +import net.minecraft.world.level.levelgen.placement.PlacedFeature; +import net.minecraft.world.level.levelgen.placement.PlacementContext; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; +import net.neoforged.neoforge.event.EventHooks; +import net.neoforged.neoforge.event.RegisterGameTestsEvent; +import net.neoforged.neoforge.event.entity.player.PlayerInteractEvent; +import net.neoforged.neoforge.event.entity.player.PlayerEvent; + +import java.util.List; +import java.util.Optional; +import java.util.function.Consumer; + +public final class RetoldToolProgressionGameTests { + private static final Identifier EMPTY_STRUCTURE = + Identifier.withDefaultNamespace("empty"); + private static final ResourceKey COPPER_ORE_PLACEMENT = + ResourceKey.create( + Registries.PLACED_FEATURE, + Identifier.withDefaultNamespace("ore_copper") + ); + private static final ResourceKey LARGE_COPPER_ORE_PLACEMENT = + ResourceKey.create( + Registries.PLACED_FEATURE, + Identifier.withDefaultNamespace("ore_copper_large") + ); + private static final List REMOVED_TOOL_RECIPE_IDS = List.of( + "wooden_axe", + "wooden_hoe", + "wooden_pickaxe", + "wooden_shovel", + "wooden_spear", + "wooden_sword", + "stone_axe", + "stone_hoe", + "stone_pickaxe", + "stone_shovel", + "stone_spear", + "stone_sword" + ); + private static final List STEEL_EQUIPMENT_RECIPE_IDS = List.of( + "steel_sword", + "steel_shovel", + "steel_pickaxe", + "steel_axe", + "steel_hoe", + "steel_helmet", + "steel_chestplate", + "steel_leggings", + "steel_boots" + ); + private static final int LEAF_LOOT_SAMPLE_COUNT = 512; + + private RetoldToolProgressionGameTests() { + } + + public static void register( + RegisterGameTestsEvent event, + Holder> environment + ) { + registerTest( + event, + environment, + "tool_progression_harvest_rules_enforce_material_ladder", + RetoldToolProgressionGameTests::harvestRulesEnforceMaterialLadder + ); + registerTest( + event, + environment, + "tool_progression_recipes_enforce_opening_loop", + RetoldToolProgressionGameTests::recipesEnforceOpeningLoop + ); + registerTest( + event, + environment, + "tool_progression_leaves_supply_sticks", + RetoldToolProgressionGameTests::leavesSupplySticks + ); + registerTest( + event, + environment, + "tool_progression_campfires_require_ignition", + RetoldToolProgressionGameTests::campfiresRequireIgnition + ); + registerTest( + event, + environment, + "tool_progression_copper_generation_is_reduced", + RetoldToolProgressionGameTests::copperGenerationIsReduced + ); + } + + private static void copperGenerationIsReduced(GameTestHelper helper) { + assertCopperPlacement(helper, COPPER_ORE_PLACEMENT, 10); + assertCopperPlacement(helper, LARGE_COPPER_ORE_PLACEMENT, 20); + helper.succeed(); + } + + private static void assertCopperPlacement( + GameTestHelper helper, + ResourceKey key, + int expectedVeinSize + ) { + var level = helper.getLevel(); + PlacedFeature placedFeature = level.registryAccess() + .lookupOrThrow(Registries.PLACED_FEATURE) + .getOrThrow(key) + .value(); + CountPlacement countPlacement = placedFeature.placement() + .stream() + .filter(CountPlacement.class::isInstance) + .map(CountPlacement.class::cast) + .findFirst() + .orElseThrow(() -> helper.assertionException( + key.identifier() + " must use count placement" + )); + PlacementContext context = new PlacementContext( + level, + level.getChunkSource().getGenerator(), + Optional.of(placedFeature) + ); + List sampleOrigins = List.of( + new BlockPos(0, 48, 0), + new BlockPos(15, 48, 15), + new BlockPos(16, 48, 16) + ); + + for (int sample = 0; sample < sampleOrigins.size(); sample++) { + long placements = countPlacement.getPositions( + context, + RandomSource.create(1000L + sample), + sampleOrigins.get(sample) + ).count(); + helper.assertTrue( + placements == 6, + key.identifier() + + " must make six attempts across seed and chunk-border samples" + ); + } + + helper.assertTrue( + placedFeature.feature().value().config() + instanceof OreConfiguration oreConfiguration + && oreConfiguration.size == expectedVeinSize, + key.identifier() + + " must preserve rewarding vanilla vein size " + + expectedVeinSize + ); + } + + private static void campfiresRequireIgnition(GameTestHelper helper) { + BlockPos supportPos = helper.absolutePos(BlockPos.ZERO); + BlockPos campfirePos = supportPos.above(); + helper.getLevel().setBlockAndUpdate( + supportPos, + Blocks.STONE.defaultBlockState() + ); + ServerPlayer player = (ServerPlayer) helper.makeMockServerPlayer( + GameType.SURVIVAL + ); + ItemStack campfire = new ItemStack(Items.CAMPFIRE); + player.setItemInHand(InteractionHand.MAIN_HAND, campfire); + BlockHitResult placementHit = new BlockHitResult( + Vec3.atCenterOf(supportPos), + Direction.UP, + supportPos, + false + ); + BlockState campfirePlacement = Blocks.CAMPFIRE.getStateForPlacement( + new BlockPlaceContext( + player, + InteractionHand.MAIN_HAND, + campfire, + placementHit + ) + ); + helper.assertTrue( + campfirePlacement != null, + "A Campfire must provide an initial placement state" + ); + helper.assertFalse( + campfirePlacement.getValue(CampfireBlock.LIT), + "A Campfire's initial placement state must already be unlit" + ); + + helper.getLevel().setBlockAndUpdate(campfirePos, campfirePlacement); + ItemStack flint = new ItemStack(Items.FLINT, 2); + player.setItemInHand(InteractionHand.MAIN_HAND, flint); + BlockHitResult hit = new BlockHitResult( + Vec3.atCenterOf(campfirePos), + Direction.UP, + campfirePos, + false + ); + PlayerInteractEvent.RightClickBlock flintUse = + new PlayerInteractEvent.RightClickBlock( + player, + InteractionHand.MAIN_HAND, + campfirePos, + hit + ); + RetoldCampfireProgressionEvents.onFlintUsedOnCampfire(flintUse); + helper.assertTrue( + flintUse.isCanceled() + && flintUse.getCancellationResult() + == InteractionResult.SUCCESS, + "Bare Flint must handle the Campfire ignition interaction" + ); + helper.assertTrue( + helper.getLevel() + .getBlockState(campfirePos) + .getValue(CampfireBlock.LIT), + "Bare Flint must light an unlit Campfire" + ); + helper.assertTrue( + flint.getCount() == 1, + "Lighting a Campfire with bare Flint must consume one Flint" + ); + + helper.getLevel().setBlockAndUpdate(campfirePos, campfirePlacement); + ItemStack flintAndSteel = new ItemStack(Items.FLINT_AND_STEEL); + player.setItemInHand(InteractionHand.MAIN_HAND, flintAndSteel); + Items.FLINT_AND_STEEL.useOn(new UseOnContext( + player, + InteractionHand.MAIN_HAND, + hit + )); + helper.assertTrue( + helper.getLevel() + .getBlockState(campfirePos) + .getValue(CampfireBlock.LIT), + "Flint and Steel must retain vanilla Campfire ignition" + ); + helper.assertTrue( + flintAndSteel.getDamageValue() == 1, + "Flint and Steel must use durability instead of being consumed" + ); + + helper.succeed(); + } + + private static void leavesSupplySticks(GameTestHelper helper) { + int unenchantedSticks = countOakLeafSticks( + helper, + ItemStack.EMPTY, + LEAF_LOOT_SAMPLE_COUNT + ); + helper.assertTrue( + unenchantedSticks >= 100, + "Retold leaves must provide substantially more Sticks than the vanilla 2% pool" + ); + + ItemStack fortuneTool = new ItemStack(Items.DIAMOND_PICKAXE); + var enchantments = helper.getLevel() + .registryAccess() + .lookupOrThrow(Registries.ENCHANTMENT); + fortuneTool.enchant( + enchantments.getOrThrow(Enchantments.FORTUNE), + 3 + ); + int fortuneSticks = countOakLeafSticks( + helper, + fortuneTool, + LEAF_LOOT_SAMPLE_COUNT + ); + helper.assertTrue( + fortuneSticks > unenchantedSticks, + "Fortune III must improve Retold's supplemental leaf Stick chance" + ); + + helper.assertTrue( + countOakLeafSticks( + helper, + new ItemStack(Items.SHEARS), + LEAF_LOOT_SAMPLE_COUNT + ) == 0, + "Shears must keep the leaf-block harvest path without extra Sticks" + ); + + ItemStack silkTouchTool = new ItemStack(Items.DIAMOND_PICKAXE); + silkTouchTool.enchant( + enchantments.getOrThrow(Enchantments.SILK_TOUCH), + 1 + ); + helper.assertTrue( + countOakLeafSticks( + helper, + silkTouchTool, + LEAF_LOOT_SAMPLE_COUNT + ) == 0, + "Silk Touch must keep the leaf-block harvest path without extra Sticks" + ); + float baseChance = RetoldLeafStickLootModifier.chanceForFortune(0); + float fortuneThreeChance = + RetoldLeafStickLootModifier.chanceForFortune(3); + helper.assertTrue( + Math.abs(baseChance - 0.20F) < 0.0001F + && Math.abs(fortuneThreeChance - 0.35F) < 0.0001F, + "Leaf Stick chances must remain 20% base and 35% at Fortune III" + ); + + helper.succeed(); + } + + private static int countOakLeafSticks( + GameTestHelper helper, + ItemStack tool, + int samples + ) { + var level = helper.getLevel(); + LootParams params = new LootParams.Builder(level) + .withParameter( + LootContextParams.ORIGIN, + Vec3.atCenterOf(helper.absolutePos(BlockPos.ZERO)) + ) + .withParameter( + LootContextParams.BLOCK_STATE, + Blocks.OAK_LEAVES.defaultBlockState() + ) + .withParameter(LootContextParams.TOOL, tool) + .create(LootContextParamSets.BLOCK); + LootTable lootTable = level.getServer() + .reloadableRegistries() + .getLootTable( + Blocks.OAK_LEAVES.getLootTable().orElseThrow() + ); + int sticks = 0; + + for (long seed = 1L; seed <= samples; seed++) { + for (ItemStack stack : lootTable.getRandomItems(params, seed)) { + if (stack.is(Items.STICK)) { + sticks += stack.getCount(); + } + } + } + + return sticks; + } + + private static void harvestRulesEnforceMaterialLadder( + GameTestHelper helper + ) { + ServerPlayer player = (ServerPlayer) helper.makeMockServerPlayer( + GameType.SURVIVAL + ); + var level = helper.getLevel(); + var pos = helper.absolutePos(BlockPos.ZERO); + + player.setItemInHand(InteractionHand.MAIN_HAND, ItemStack.EMPTY); + helper.assertFalse( + EventHooks.doPlayerHarvestCheck( + player, + Blocks.OAK_LOG.defaultBlockState(), + level, + pos + ), + "Logs must not drop when broken by hand" + ); + + ItemStack flintMultiTool = new ItemStack( + RetoldBlocks.FLINT_MULTI_TOOL.get() + ); + player.setItemInHand(InteractionHand.MAIN_HAND, flintMultiTool); + helper.assertTrue( + EventHooks.doPlayerHarvestCheck( + player, + Blocks.OAK_LOG.defaultBlockState(), + level, + pos + ), + "The Flint Multi-tool must harvest logs" + ); + helper.assertTrue( + flintMultiTool.isCorrectToolForDrops( + Blocks.COPPER_ORE.defaultBlockState() + ), + "The Flint Multi-tool must harvest exposed Copper ore" + ); + helper.assertTrue( + flintMultiTool.isCorrectToolForDrops( + Blocks.TUFF.defaultBlockState() + ), + "The Flint Multi-tool must harvest soft early stone" + ); + helper.assertFalse( + flintMultiTool.isCorrectToolForDrops( + Blocks.STONE.defaultBlockState() + ), + "The Flint Multi-tool must not harvest normal Stone" + ); + helper.assertTrue( + flintMultiTool.getMaxDamage() == 48, + "The Flint Multi-tool must use the approved provisional durability" + ); + + player.setItemInHand( + InteractionHand.MAIN_HAND, + new ItemStack(Items.COPPER_PICKAXE) + ); + helper.assertTrue( + EventHooks.doPlayerHarvestCheck( + player, + Blocks.STONE.defaultBlockState(), + level, + pos + ), + "A Copper Pickaxe must harvest Stone and receive Cobblestone" + ); + + PlayerEvent.BreakSpeed copperStoneSpeed = + new PlayerEvent.BreakSpeed( + player, + Blocks.STONE.defaultBlockState(), + 5.0F, + pos + ); + RetoldToolProgressionEvents.onBreakSpeed(copperStoneSpeed); + helper.assertTrue( + Math.abs(copperStoneSpeed.getNewSpeed() - 1.25F) < 0.0001F, + "A Copper Pickaxe must mine Stone at 25% of normal speed" + ); + + player.setItemInHand( + InteractionHand.MAIN_HAND, + new ItemStack(Items.IRON_PICKAXE) + ); + PlayerEvent.BreakSpeed ironStoneSpeed = + new PlayerEvent.BreakSpeed( + player, + Blocks.STONE.defaultBlockState(), + 6.0F, + pos + ); + RetoldToolProgressionEvents.onBreakSpeed(ironStoneSpeed); + helper.assertTrue( + ironStoneSpeed.getNewSpeed() == 6.0F, + "Iron must retain its normal practical Stone-mining speed" + ); + + PlayerEvent.BreakSpeed ironDeepslateSpeed = + new PlayerEvent.BreakSpeed( + player, + Blocks.DEEPSLATE.defaultBlockState(), + 6.0F, + pos + ); + RetoldToolProgressionEvents.onBreakSpeed(ironDeepslateSpeed); + helper.assertTrue( + ironDeepslateSpeed.getNewSpeed() == 1.5F, + "Iron must mine Deepslate at 25% speed before Steel" + ); + + ItemStack steelPickaxe = new ItemStack( + RetoldBlocks.STEEL_PICKAXE.get() + ); + player.setItemInHand(InteractionHand.MAIN_HAND, steelPickaxe); + PlayerEvent.BreakSpeed steelDeepslateSpeed = + new PlayerEvent.BreakSpeed( + player, + Blocks.DEEPSLATE.defaultBlockState(), + 7.0F, + pos + ); + RetoldToolProgressionEvents.onBreakSpeed(steelDeepslateSpeed); + helper.assertTrue( + steelDeepslateSpeed.getNewSpeed() == 7.0F, + "Steel must make Deepslate practical" + ); + helper.assertTrue( + steelPickaxe.isCorrectToolForDrops( + Blocks.DEEPSLATE_DIAMOND_ORE.defaultBlockState() + ), + "Steel must harvest deep Diamond ore" + ); + helper.assertFalse( + steelPickaxe.isCorrectToolForDrops( + Blocks.OBSIDIAN.defaultBlockState() + ), + "Steel must not replace Diamond for Obsidian access" + ); + helper.assertTrue( + steelPickaxe.getMaxDamage() == 750, + "Steel tools must use the approved provisional durability" + ); + helper.assertTrue( + steelPickaxe.is(ItemTags.PICKAXES), + "Steel tools must join their vanilla item-family tags" + ); + helper.assertTrue( + Items.IRON_PICKAXE.getDefaultInstance().is(ItemTags.PICKAXES), + "Steel tag additions must preserve vanilla tool entries" + ); + ItemStack steelHelmet = RetoldBlocks.STEEL_HELMET.get() + .getDefaultInstance(); + helper.assertTrue( + steelHelmet.getMaxDamage() == 275, + "Steel armor must use the provisional 25x durability" + ); + helper.assertTrue( + steelHelmet.is(ItemTags.HEAD_ARMOR) + && steelHelmet.is(ItemTags.TRIMMABLE_ARMOR), + "Steel armor must support normal armor systems and trims" + ); + + var enchantments = helper.getLevel() + .registryAccess() + .lookupOrThrow(Registries.ENCHANTMENT); + ItemStack diamondPickaxe = Items.DIAMOND_PICKAXE + .getDefaultInstance(); + helper.assertTrue( + diamondPickaxe.getMaxDamage() == 64, + "Unenchanted Diamond tools must use fragile durability" + ); + diamondPickaxe.enchant( + enchantments.getOrThrow(Enchantments.EFFICIENCY), + 1 + ); + helper.assertTrue( + diamondPickaxe.getMaxDamage() == 1561, + "Any enchantment must restore full Diamond tool durability" + ); + diamondPickaxe.set( + DataComponents.ENCHANTMENTS, + ItemEnchantments.EMPTY + ); + helper.assertTrue( + diamondPickaxe.getMaxDamage() == 64, + "Removing all enchantments must restore fragile durability" + ); + + diamondPickaxe.enchant( + enchantments.getOrThrow(Enchantments.EFFICIENCY), + 1 + ); + diamondPickaxe.setDamageValue(1000); + diamondPickaxe.set( + DataComponents.ENCHANTMENTS, + ItemEnchantments.EMPTY + ); + helper.assertTrue( + diamondPickaxe.getMaxDamage() == 1001 + && diamondPickaxe.nextDamageWillBreak(), + "Stripping heavily damaged Diamond gear must leave one use instead of an invalid stack" + ); + + ItemStack diamondHelmet = Items.DIAMOND_HELMET + .getDefaultInstance(); + helper.assertTrue( + diamondHelmet.getMaxDamage() == 66, + "Unenchanted Diamond armor must use 6x durability" + ); + diamondHelmet.enchant( + enchantments.getOrThrow(Enchantments.PROTECTION), + 1 + ); + helper.assertTrue( + diamondHelmet.getMaxDamage() == 363, + "Any enchantment must restore full Diamond armor durability" + ); + diamondHelmet.set( + DataComponents.ENCHANTMENTS, + ItemEnchantments.EMPTY + ); + helper.assertTrue( + diamondHelmet.getMaxDamage() == 66, + "Stripped Diamond armor must become fragile again" + ); + + helper.succeed(); + } + + private static void recipesEnforceOpeningLoop(GameTestHelper helper) { + RecipeManager recipes = helper.getLevel().getServer().getRecipeManager(); + + for (String removedRecipeId : REMOVED_TOOL_RECIPE_IDS) { + helper.assertTrue( + recipes.byKey(minecraftRecipeKey(removedRecipeId)).isEmpty(), + "Wooden and Stone tool recipes must be removed: " + + removedRecipeId + ); + } + + CraftingInput flintMultiToolInput = CraftingInput.of( + 2, + 2, + List.of( + new ItemStack(Items.FLINT), + new ItemStack(Items.FLINT), + ItemStack.EMPTY, + new ItemStack(Items.STICK) + ) + ); + RecipeHolder flintMultiToolRecipe = recipes.getRecipeFor( + RecipeType.CRAFTING, + flintMultiToolInput, + helper.getLevel() + ).orElseThrow(() -> helper.assertionException( + "The Flint Multi-tool must be craftable in the 2x2 inventory grid" + )); + helper.assertTrue( + flintMultiToolRecipe.id().equals( + retoldRecipeKey("flint_multi_tool") + ), + "The confirmed two-Flint-and-one-Stick shape must select the Flint Multi-tool recipe" + ); + helper.assertTrue( + flintMultiToolRecipe.value() + .assemble(flintMultiToolInput) + .is(RetoldBlocks.FLINT_MULTI_TOOL.get()), + "The opening recipe must produce the Flint Multi-tool" + ); + + CraftingInput unfueledCampfireInput = campfireInput(ItemStack.EMPTY); + RecipeHolder loadedCampfireRecipe = recipes.byKey( + minecraftRecipeKey("campfire") + ).orElseThrow(() -> helper.assertionException( + "The replaced Campfire recipe must load" + )); + helper.assertTrue( + loadedCampfireRecipe.value() instanceof CraftingRecipe, + "The replaced Campfire recipe must remain a crafting recipe" + ); + CraftingRecipe unfueledCampfireRecipe = + (CraftingRecipe) loadedCampfireRecipe.value(); + helper.assertTrue( + unfueledCampfireRecipe.matches( + unfueledCampfireInput, + helper.getLevel() + ) && unfueledCampfireRecipe + .assemble(unfueledCampfireInput) + .is(Items.CAMPFIRE), + "The Campfire recipe must no longer require Coal or Flint" + ); + + CraftingInput oldCampfireInput = campfireInput( + Items.COAL.getDefaultInstance() + ); + boolean coalStillCraftsCampfire = recipes.getRecipeFor( + RecipeType.CRAFTING, + oldCampfireInput, + helper.getLevel() + ).map(recipe -> recipe.value() + .assemble(oldCampfireInput) + .is(Items.CAMPFIRE) + ).orElse(false); + helper.assertFalse( + coalStillCraftsCampfire, + "The old Coal-based Campfire recipe must be replaced" + ); + + assertCampfireCookingResult( + helper, + recipes, + Items.CLAY_BALL.getDefaultInstance(), + Items.BRICK, + "A Campfire must fire Clay Balls into Bricks" + ); + + CraftingInput brickFurnaceInput = furnaceRingInput(Items.BRICK); + RecipeHolder brickFurnaceRecipe = recipes.getRecipeFor( + RecipeType.CRAFTING, + brickFurnaceInput, + helper.getLevel() + ).orElseThrow(() -> helper.assertionException( + "Eight Bricks in a ring must craft the Brick Furnace" + )); + helper.assertTrue( + brickFurnaceRecipe.id().equals(minecraftRecipeKey("smoker")), + "The Brick Furnace must reuse the vanilla Smoker recipe identity" + ); + helper.assertTrue( + brickFurnaceRecipe.value() + .assemble(brickFurnaceInput) + .is(Items.SMOKER), + "The Brick Furnace recipe must produce the repurposed Smoker block" + ); + + CraftingInput unfiredClayRing = furnaceRingInput(Items.CLAY_BALL); + boolean unfiredClayCraftsFurnace = recipes.getRecipeFor( + RecipeType.CRAFTING, + unfiredClayRing, + helper.getLevel() + ).map(recipe -> recipe.value() + .assemble(unfiredClayRing) + .is(Items.SMOKER) + ).orElse(false); + helper.assertFalse( + unfiredClayCraftsFurnace, + "Unfired Clay Balls must not bypass the Campfire Brick step" + ); + + assertSmokingResult( + helper, + recipes, + Items.RAW_COPPER.getDefaultInstance(), + Items.COPPER_INGOT, + "The Brick Furnace must smelt Raw Copper" + ); + assertSmokingResult( + helper, + recipes, + Items.OAK_LOG.getDefaultInstance(), + Items.CHARCOAL, + "The Brick Furnace must make Charcoal from burnable logs" + ); + assertBlastingResult( + helper, + recipes, + Items.IRON_INGOT.getDefaultInstance(), + RetoldBlocks.STEEL_INGOT.get(), + "The Blast Furnace must process Iron directly into Steel" + ); + + for (String steelRecipeId : STEEL_EQUIPMENT_RECIPE_IDS) { + helper.assertTrue( + recipes.byKey(retoldRecipeKey(steelRecipeId)).isPresent(), + "Steel equipment recipe must load: " + steelRecipeId + ); + } + + CraftingInput steelPickaxeInput = CraftingInput.of( + 3, + 3, + List.of( + RetoldBlocks.STEEL_INGOT.get().getDefaultInstance(), + RetoldBlocks.STEEL_INGOT.get().getDefaultInstance(), + RetoldBlocks.STEEL_INGOT.get().getDefaultInstance(), + ItemStack.EMPTY, + Items.STICK.getDefaultInstance(), + ItemStack.EMPTY, + ItemStack.EMPTY, + Items.STICK.getDefaultInstance(), + ItemStack.EMPTY + ) + ); + RecipeHolder steelPickaxeRecipe = recipes.getRecipeFor( + RecipeType.CRAFTING, + steelPickaxeInput, + helper.getLevel() + ).orElseThrow(() -> helper.assertionException( + "Steel must use the familiar Pickaxe crafting shape" + )); + helper.assertTrue( + steelPickaxeRecipe.value() + .assemble(steelPickaxeInput) + .is(RetoldBlocks.STEEL_PICKAXE.get()), + "The Steel Pickaxe recipe must produce the registered tool" + ); + + helper.assertTrue( + recipes.byKey(minecraftRecipeKey("furnace")).isPresent(), + "The normal Furnace recipe must remain available after Copper" + ); + helper.succeed(); + } + + private static void assertSmokingResult( + GameTestHelper helper, + RecipeManager recipes, + ItemStack ingredient, + Item expectedResult, + String message + ) { + SingleRecipeInput input = new SingleRecipeInput(ingredient); + RecipeHolder recipe = recipes.getRecipeFor( + RecipeType.SMOKING, + input, + helper.getLevel() + ).orElseThrow(() -> helper.assertionException(message)); + helper.assertTrue(recipe.value().assemble(input).is(expectedResult), message); + } + + private static void assertCampfireCookingResult( + GameTestHelper helper, + RecipeManager recipes, + ItemStack ingredient, + Item expectedResult, + String message + ) { + SingleRecipeInput input = new SingleRecipeInput(ingredient); + RecipeHolder recipe = recipes.getRecipeFor( + RecipeType.CAMPFIRE_COOKING, + input, + helper.getLevel() + ).orElseThrow(() -> helper.assertionException(message)); + helper.assertTrue( + recipe.id().equals(retoldRecipeKey( + "brick_from_campfire_cooking_clay_ball" + )), + "The Brick recipe must be Retold's explicit Campfire step" + ); + helper.assertTrue(recipe.value().assemble(input).is(expectedResult), message); + } + + private static CraftingInput furnaceRingInput(Item ingredient) { + return CraftingInput.of( + 3, + 3, + List.of( + new ItemStack(ingredient), + new ItemStack(ingredient), + new ItemStack(ingredient), + new ItemStack(ingredient), + ItemStack.EMPTY, + new ItemStack(ingredient), + new ItemStack(ingredient), + new ItemStack(ingredient), + new ItemStack(ingredient) + ) + ); + } + + private static CraftingInput campfireInput(ItemStack center) { + return CraftingInput.of( + 3, + 3, + List.of( + ItemStack.EMPTY, + Items.STICK.getDefaultInstance(), + ItemStack.EMPTY, + Items.STICK.getDefaultInstance(), + center, + Items.STICK.getDefaultInstance(), + Items.OAK_LOG.getDefaultInstance(), + Items.OAK_LOG.getDefaultInstance(), + Items.OAK_LOG.getDefaultInstance() + ) + ); + } + + private static void assertBlastingResult( + GameTestHelper helper, + RecipeManager recipes, + ItemStack ingredient, + Item expectedResult, + String message + ) { + SingleRecipeInput input = new SingleRecipeInput(ingredient); + RecipeHolder recipe = recipes.getRecipeFor( + RecipeType.BLASTING, + input, + helper.getLevel() + ).orElseThrow(() -> helper.assertionException(message)); + helper.assertTrue(recipe.value().assemble(input).is(expectedResult), message); + } + + private static ResourceKey> minecraftRecipeKey(String path) { + return ResourceKey.create( + Registries.RECIPE, + Identifier.withDefaultNamespace(path) + ); + } + + private static ResourceKey> retoldRecipeKey(String path) { + return ResourceKey.create( + Registries.RECIPE, + Identifier.fromNamespaceAndPath("retold", path) + ); + } + + private static void registerTest( + RegisterGameTestsEvent event, + Holder> environment, + String name, + Consumer test + ) { + TestData>> testData = + new TestData<>( + environment, + EMPTY_STRUCTURE, + 40, + 0, + true + ); + + event.registerTest( + retoldId(name), + new InlineGameTest(testData, test) + ); + } + + private static Identifier retoldId(String path) { + return Identifier.fromNamespaceAndPath("retold", path); + } + + private static final class InlineGameTest extends FunctionGameTestInstance { + private final Consumer test; + + private InlineGameTest( + TestData>> testData, + Consumer test + ) { + super(BuiltinTestFunctions.ALWAYS_PASS, testData); + this.test = test; + } + + @Override + public void run(GameTestHelper helper) { + test.accept(helper); + } + } +} diff --git a/src/main/java/cz/xefensor/retold/registry/RetoldBlocks.java b/src/main/java/cz/xefensor/retold/registry/RetoldBlocks.java index cf3764c..06499f4 100644 --- a/src/main/java/cz/xefensor/retold/registry/RetoldBlocks.java +++ b/src/main/java/cz/xefensor/retold/registry/RetoldBlocks.java @@ -14,12 +14,20 @@ import cz.xefensor.retold.block.AnimalFeederBlock; import net.minecraft.core.registries.Registries; import net.minecraft.resources.ResourceKey; +import net.minecraft.sounds.SoundEvents; import net.minecraft.util.ColorRGBA; import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.AxeItem; +import net.minecraft.world.item.HoeItem; import net.minecraft.world.item.Item; import net.minecraft.world.item.Items; import net.minecraft.world.item.Rarity; +import net.minecraft.world.item.ShovelItem; import net.minecraft.world.item.SpawnEggItem; +import net.minecraft.world.item.ToolMaterial; +import net.minecraft.world.item.equipment.ArmorMaterial; +import net.minecraft.world.item.equipment.ArmorType; +import net.minecraft.world.item.equipment.EquipmentAssets; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.ColoredFallingBlock; @@ -33,10 +41,140 @@ import net.neoforged.neoforge.registries.DeferredItem; import net.neoforged.neoforge.registries.DeferredRegister; +import java.util.Map; + public final class RetoldBlocks { public static final DeferredRegister.Blocks BLOCKS = DeferredRegister.createBlocks(Retold.MODID); public static final DeferredRegister.Items ITEMS = DeferredRegister.createItems(Retold.MODID); + private static final ToolMaterial FLINT_MULTI_TOOL_MATERIAL = + new ToolMaterial( + RetoldTags.INCORRECT_FOR_FLINT_MULTI_TOOL, + 48, + 2.0F, + 0.0F, + 5, + RetoldTags.FLINT_MULTI_TOOL_REPAIR_MATERIALS + ); + private static final ToolMaterial STEEL_TOOL_MATERIAL = + new ToolMaterial( + RetoldTags.INCORRECT_FOR_STEEL_TOOL, + 750, + 7.0F, + 2.5F, + 12, + RetoldTags.STEEL_REPAIR_MATERIALS + ); + private static final ArmorMaterial STEEL_ARMOR_MATERIAL = + new ArmorMaterial( + 25, + Map.of( + ArmorType.BOOTS, 3, + ArmorType.LEGGINGS, 6, + ArmorType.CHESTPLATE, 7, + ArmorType.HELMET, 3, + ArmorType.BODY, 9 + ), + 12, + SoundEvents.ARMOR_EQUIP_IRON, + 1.0F, + 0.0F, + RetoldTags.STEEL_REPAIR_MATERIALS, + EquipmentAssets.IRON + ); + + public static final DeferredItem FLINT_MULTI_TOOL = ITEMS.registerItem( + "flint_multi_tool", + Item::new, + properties -> properties.tool( + FLINT_MULTI_TOOL_MATERIAL, + RetoldTags.FLINT_MULTI_TOOL_MINEABLE, + 1.0F, + -2.8F, + 0.0F + ) + ); + public static final DeferredItem STEEL_INGOT = ITEMS.registerSimpleItem( + "steel_ingot" + ); + public static final DeferredItem STEEL_SWORD = ITEMS.registerItem( + "steel_sword", + Item::new, + properties -> properties.sword( + STEEL_TOOL_MATERIAL, + 3.0F, + -2.4F + ) + ); + public static final DeferredItem STEEL_SHOVEL = ITEMS.registerItem( + "steel_shovel", + properties -> new ShovelItem( + STEEL_TOOL_MATERIAL, + 1.5F, + -3.0F, + properties + ) + ); + public static final DeferredItem STEEL_PICKAXE = ITEMS.registerItem( + "steel_pickaxe", + Item::new, + properties -> properties.pickaxe( + STEEL_TOOL_MATERIAL, + 1.0F, + -2.8F + ) + ); + public static final DeferredItem STEEL_AXE = ITEMS.registerItem( + "steel_axe", + properties -> new AxeItem( + STEEL_TOOL_MATERIAL, + 5.5F, + -3.05F, + properties + ) + ); + public static final DeferredItem STEEL_HOE = ITEMS.registerItem( + "steel_hoe", + properties -> new HoeItem( + STEEL_TOOL_MATERIAL, + -2.5F, + -0.5F, + properties + ) + ); + public static final DeferredItem STEEL_HELMET = ITEMS.registerItem( + "steel_helmet", + Item::new, + properties -> properties.humanoidArmor( + STEEL_ARMOR_MATERIAL, + ArmorType.HELMET + ) + ); + public static final DeferredItem STEEL_CHESTPLATE = ITEMS.registerItem( + "steel_chestplate", + Item::new, + properties -> properties.humanoidArmor( + STEEL_ARMOR_MATERIAL, + ArmorType.CHESTPLATE + ) + ); + public static final DeferredItem STEEL_LEGGINGS = ITEMS.registerItem( + "steel_leggings", + Item::new, + properties -> properties.humanoidArmor( + STEEL_ARMOR_MATERIAL, + ArmorType.LEGGINGS + ) + ); + public static final DeferredItem STEEL_BOOTS = ITEMS.registerItem( + "steel_boots", + Item::new, + properties -> properties.humanoidArmor( + STEEL_ARMOR_MATERIAL, + ArmorType.BOOTS + ) + ); + public static final DeferredItem WATER_ELEMENT = ITEMS.registerItem( "water_element", WaterElementItem::new, diff --git a/src/main/java/cz/xefensor/retold/registry/RetoldCreativeModeTabs.java b/src/main/java/cz/xefensor/retold/registry/RetoldCreativeModeTabs.java index a51fc09..378141f 100644 --- a/src/main/java/cz/xefensor/retold/registry/RetoldCreativeModeTabs.java +++ b/src/main/java/cz/xefensor/retold/registry/RetoldCreativeModeTabs.java @@ -26,6 +26,8 @@ private static void buildContents(BuildCreativeModeTabContentsEvent event) { addFunctionalBlocks(event); } else if (CreativeModeTabs.TOOLS_AND_UTILITIES.equals(event.getTabKey())) { addToolsAndUtilities(event); + } else if (CreativeModeTabs.COMBAT.equals(event.getTabKey())) { + addCombat(event); } else if (CreativeModeTabs.INGREDIENTS.equals(event.getTabKey())) { addIngredients(event); } else if (CreativeModeTabs.SPAWN_EGGS.equals(event.getTabKey())) { @@ -93,15 +95,42 @@ private static void addFunctionalBlocks(BuildCreativeModeTabContentsEvent event) } private static void addToolsAndUtilities(BuildCreativeModeTabContentsEvent event) { + insertAfter( + event, + Items.FLINT_AND_STEEL, + RetoldBlocks.FLINT_MULTI_TOOL.get() + ); insertAfter( event, Items.PALE_OAK_CHEST_BOAT, RetoldAenderWood.AENDER_BOAT_ITEM.get(), RetoldAenderWood.AENDER_CHEST_BOAT_ITEM.get() ); + insertAfter(event, Items.IRON_SHOVEL, RetoldBlocks.STEEL_SHOVEL.get()); + insertAfter(event, Items.IRON_PICKAXE, RetoldBlocks.STEEL_PICKAXE.get()); + insertAfter(event, Items.IRON_AXE, RetoldBlocks.STEEL_AXE.get()); + insertAfter(event, Items.IRON_HOE, RetoldBlocks.STEEL_HOE.get()); + } + + private static void addCombat(BuildCreativeModeTabContentsEvent event) { + insertAfter(event, Items.IRON_SWORD, RetoldBlocks.STEEL_SWORD.get()); + insertAfter(event, Items.IRON_AXE, RetoldBlocks.STEEL_AXE.get()); + insertAfter(event, Items.IRON_HELMET, RetoldBlocks.STEEL_HELMET.get()); + insertAfter( + event, + Items.IRON_CHESTPLATE, + RetoldBlocks.STEEL_CHESTPLATE.get() + ); + insertAfter( + event, + Items.IRON_LEGGINGS, + RetoldBlocks.STEEL_LEGGINGS.get() + ); + insertAfter(event, Items.IRON_BOOTS, RetoldBlocks.STEEL_BOOTS.get()); } private static void addIngredients(BuildCreativeModeTabContentsEvent event) { + insertAfter(event, Items.IRON_INGOT, RetoldBlocks.STEEL_INGOT.get()); insertAfter(event, Items.RAW_GOLD, RetoldBlocks.RAW_AENDERITE.get()); insertAfter(event, Items.NETHERITE_INGOT, RetoldBlocks.AENDERITE_INGOT.get()); insertAfter( diff --git a/src/main/java/cz/xefensor/retold/registry/RetoldTags.java b/src/main/java/cz/xefensor/retold/registry/RetoldTags.java index ea9b70e..ba545e7 100644 --- a/src/main/java/cz/xefensor/retold/registry/RetoldTags.java +++ b/src/main/java/cz/xefensor/retold/registry/RetoldTags.java @@ -13,6 +13,70 @@ public final class RetoldTags { Registries.ITEM, Identifier.fromNamespaceAndPath(Retold.MODID, "torch_igniters") ); + public static final TagKey FLINT_MULTI_TOOL_REPAIR_MATERIALS = + TagKey.create( + Registries.ITEM, + Identifier.fromNamespaceAndPath( + Retold.MODID, + "flint_multi_tool_repair_materials" + ) + ); + public static final TagKey STEEL_REPAIR_MATERIALS = + TagKey.create( + Registries.ITEM, + Identifier.fromNamespaceAndPath( + Retold.MODID, + "steel_repair_materials" + ) + ); + public static final TagKey FRAGILE_UNENCHANTED_DIAMOND_TOOLS = + TagKey.create( + Registries.ITEM, + Identifier.fromNamespaceAndPath( + Retold.MODID, + "fragile_unenchanted_diamond_tools" + ) + ); + public static final TagKey FRAGILE_UNENCHANTED_DIAMOND_ARMOR = + TagKey.create( + Registries.ITEM, + Identifier.fromNamespaceAndPath( + Retold.MODID, + "fragile_unenchanted_diamond_armor" + ) + ); + public static final TagKey FLINT_MULTI_TOOL_MINEABLE = + TagKey.create( + Registries.BLOCK, + Identifier.fromNamespaceAndPath( + Retold.MODID, + "mineable/flint_multi_tool" + ) + ); + public static final TagKey INCORRECT_FOR_FLINT_MULTI_TOOL = + TagKey.create( + Registries.BLOCK, + Identifier.fromNamespaceAndPath( + Retold.MODID, + "incorrect_for_flint_multi_tool" + ) + ); + public static final TagKey INCORRECT_FOR_STEEL_TOOL = + TagKey.create( + Registries.BLOCK, + Identifier.fromNamespaceAndPath( + Retold.MODID, + "incorrect_for_steel_tool" + ) + ); + public static final TagKey STEEL_TIER_BLOCKS = + TagKey.create( + Registries.BLOCK, + Identifier.fromNamespaceAndPath( + Retold.MODID, + "steel_tier_blocks" + ) + ); public static final TagKey WEAK_MOB_BARRIERS = TagKey.create( Registries.BLOCK, Identifier.fromNamespaceAndPath(Retold.MODID, "weak_mob_barriers") diff --git a/src/main/resources/assets/minecraft/lang/en_us.json b/src/main/resources/assets/minecraft/lang/en_us.json new file mode 100644 index 0000000..fecedf3 --- /dev/null +++ b/src/main/resources/assets/minecraft/lang/en_us.json @@ -0,0 +1,4 @@ +{ + "block.minecraft.smoker": "Brick Furnace", + "container.smoker": "Brick Furnace" +} diff --git a/src/main/resources/assets/retold/items/flint_multi_tool.json b/src/main/resources/assets/retold/items/flint_multi_tool.json new file mode 100644 index 0000000..9c787d5 --- /dev/null +++ b/src/main/resources/assets/retold/items/flint_multi_tool.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "retold:item/flint_multi_tool" + } +} diff --git a/src/main/resources/assets/retold/items/steel_axe.json b/src/main/resources/assets/retold/items/steel_axe.json new file mode 100644 index 0000000..7a0b1b5 --- /dev/null +++ b/src/main/resources/assets/retold/items/steel_axe.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "minecraft:item/iron_axe" + } +} diff --git a/src/main/resources/assets/retold/items/steel_boots.json b/src/main/resources/assets/retold/items/steel_boots.json new file mode 100644 index 0000000..745d537 --- /dev/null +++ b/src/main/resources/assets/retold/items/steel_boots.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "minecraft:item/iron_boots" + } +} diff --git a/src/main/resources/assets/retold/items/steel_chestplate.json b/src/main/resources/assets/retold/items/steel_chestplate.json new file mode 100644 index 0000000..f9546d1 --- /dev/null +++ b/src/main/resources/assets/retold/items/steel_chestplate.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "minecraft:item/iron_chestplate" + } +} diff --git a/src/main/resources/assets/retold/items/steel_helmet.json b/src/main/resources/assets/retold/items/steel_helmet.json new file mode 100644 index 0000000..e560851 --- /dev/null +++ b/src/main/resources/assets/retold/items/steel_helmet.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "minecraft:item/iron_helmet" + } +} diff --git a/src/main/resources/assets/retold/items/steel_hoe.json b/src/main/resources/assets/retold/items/steel_hoe.json new file mode 100644 index 0000000..30e9eab --- /dev/null +++ b/src/main/resources/assets/retold/items/steel_hoe.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "minecraft:item/iron_hoe" + } +} diff --git a/src/main/resources/assets/retold/items/steel_ingot.json b/src/main/resources/assets/retold/items/steel_ingot.json new file mode 100644 index 0000000..7f93d17 --- /dev/null +++ b/src/main/resources/assets/retold/items/steel_ingot.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "minecraft:item/iron_ingot" + } +} diff --git a/src/main/resources/assets/retold/items/steel_leggings.json b/src/main/resources/assets/retold/items/steel_leggings.json new file mode 100644 index 0000000..b1a9de6 --- /dev/null +++ b/src/main/resources/assets/retold/items/steel_leggings.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "minecraft:item/iron_leggings" + } +} diff --git a/src/main/resources/assets/retold/items/steel_pickaxe.json b/src/main/resources/assets/retold/items/steel_pickaxe.json new file mode 100644 index 0000000..56450cc --- /dev/null +++ b/src/main/resources/assets/retold/items/steel_pickaxe.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "minecraft:item/iron_pickaxe" + } +} diff --git a/src/main/resources/assets/retold/items/steel_shovel.json b/src/main/resources/assets/retold/items/steel_shovel.json new file mode 100644 index 0000000..33b8afe --- /dev/null +++ b/src/main/resources/assets/retold/items/steel_shovel.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "minecraft:item/iron_shovel" + } +} diff --git a/src/main/resources/assets/retold/items/steel_sword.json b/src/main/resources/assets/retold/items/steel_sword.json new file mode 100644 index 0000000..89ce108 --- /dev/null +++ b/src/main/resources/assets/retold/items/steel_sword.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "model": "minecraft:item/iron_sword" + } +} diff --git a/src/main/resources/assets/retold/lang/en_us.json b/src/main/resources/assets/retold/lang/en_us.json index d591ccd..91f41d2 100644 --- a/src/main/resources/assets/retold/lang/en_us.json +++ b/src/main/resources/assets/retold/lang/en_us.json @@ -73,6 +73,17 @@ "item.retold.aender_boat": "Aender Boat", "item.retold.aender_chest_boat": "Aender Chest Boat", "item.retold.aender_eye_spawn_egg": "Aender Eye Spawn Egg", + "item.retold.flint_multi_tool": "Flint Multi-tool", + "item.retold.steel_ingot": "Steel Ingot", + "item.retold.steel_sword": "Steel Sword", + "item.retold.steel_shovel": "Steel Shovel", + "item.retold.steel_pickaxe": "Steel Pickaxe", + "item.retold.steel_axe": "Steel Axe", + "item.retold.steel_hoe": "Steel Hoe", + "item.retold.steel_helmet": "Steel Helmet", + "item.retold.steel_chestplate": "Steel Chestplate", + "item.retold.steel_leggings": "Steel Leggings", + "item.retold.steel_boots": "Steel Boots", "item.retold.raw_aenderite": "Raw Aenderite", "item.retold.aenderite_ingot": "Aenderite Ingot", "item.retold.gale_core_spawn_egg": "Gale Core Spawn Egg", diff --git a/src/main/resources/assets/retold/models/item/flint_multi_tool.json b/src/main/resources/assets/retold/models/item/flint_multi_tool.json new file mode 100644 index 0000000..9be7868 --- /dev/null +++ b/src/main/resources/assets/retold/models/item/flint_multi_tool.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/handheld", + "textures": { + "layer0": "minecraft:item/flint" + } +} diff --git a/src/main/resources/data/c/tags/item/ingots/steel.json b/src/main/resources/data/c/tags/item/ingots/steel.json new file mode 100644 index 0000000..0892865 --- /dev/null +++ b/src/main/resources/data/c/tags/item/ingots/steel.json @@ -0,0 +1,5 @@ +{ + "values": [ + "retold:steel_ingot" + ] +} diff --git a/src/main/resources/data/minecraft/recipe/smoker.json b/src/main/resources/data/minecraft/recipe/smoker.json new file mode 100644 index 0000000..eb316c2 --- /dev/null +++ b/src/main/resources/data/minecraft/recipe/smoker.json @@ -0,0 +1,15 @@ +{ + "type": "minecraft:crafting_shaped", + "category": "misc", + "key": { + "B": "minecraft:brick" + }, + "pattern": [ + "BBB", + "B B", + "BBB" + ], + "result": { + "id": "minecraft:smoker" + } +} diff --git a/src/main/resources/data/minecraft/tags/item/axes.json b/src/main/resources/data/minecraft/tags/item/axes.json new file mode 100644 index 0000000..37f17d6 --- /dev/null +++ b/src/main/resources/data/minecraft/tags/item/axes.json @@ -0,0 +1,5 @@ +{ + "values": [ + "retold:steel_axe" + ] +} diff --git a/src/main/resources/data/minecraft/tags/item/chest_armor.json b/src/main/resources/data/minecraft/tags/item/chest_armor.json new file mode 100644 index 0000000..16d83ee --- /dev/null +++ b/src/main/resources/data/minecraft/tags/item/chest_armor.json @@ -0,0 +1,5 @@ +{ + "values": [ + "retold:steel_chestplate" + ] +} diff --git a/src/main/resources/data/minecraft/tags/item/foot_armor.json b/src/main/resources/data/minecraft/tags/item/foot_armor.json new file mode 100644 index 0000000..9605d28 --- /dev/null +++ b/src/main/resources/data/minecraft/tags/item/foot_armor.json @@ -0,0 +1,5 @@ +{ + "values": [ + "retold:steel_boots" + ] +} diff --git a/src/main/resources/data/minecraft/tags/item/head_armor.json b/src/main/resources/data/minecraft/tags/item/head_armor.json new file mode 100644 index 0000000..7f1999b --- /dev/null +++ b/src/main/resources/data/minecraft/tags/item/head_armor.json @@ -0,0 +1,5 @@ +{ + "values": [ + "retold:steel_helmet" + ] +} diff --git a/src/main/resources/data/minecraft/tags/item/hoes.json b/src/main/resources/data/minecraft/tags/item/hoes.json new file mode 100644 index 0000000..2aed5a7 --- /dev/null +++ b/src/main/resources/data/minecraft/tags/item/hoes.json @@ -0,0 +1,5 @@ +{ + "values": [ + "retold:steel_hoe" + ] +} diff --git a/src/main/resources/data/minecraft/tags/item/leg_armor.json b/src/main/resources/data/minecraft/tags/item/leg_armor.json new file mode 100644 index 0000000..56366b3 --- /dev/null +++ b/src/main/resources/data/minecraft/tags/item/leg_armor.json @@ -0,0 +1,5 @@ +{ + "values": [ + "retold:steel_leggings" + ] +} diff --git a/src/main/resources/data/minecraft/tags/item/pickaxes.json b/src/main/resources/data/minecraft/tags/item/pickaxes.json new file mode 100644 index 0000000..220b71a --- /dev/null +++ b/src/main/resources/data/minecraft/tags/item/pickaxes.json @@ -0,0 +1,5 @@ +{ + "values": [ + "retold:steel_pickaxe" + ] +} diff --git a/src/main/resources/data/minecraft/tags/item/shovels.json b/src/main/resources/data/minecraft/tags/item/shovels.json new file mode 100644 index 0000000..b3703b5 --- /dev/null +++ b/src/main/resources/data/minecraft/tags/item/shovels.json @@ -0,0 +1,5 @@ +{ + "values": [ + "retold:steel_shovel" + ] +} diff --git a/src/main/resources/data/minecraft/tags/item/swords.json b/src/main/resources/data/minecraft/tags/item/swords.json new file mode 100644 index 0000000..bbe485f --- /dev/null +++ b/src/main/resources/data/minecraft/tags/item/swords.json @@ -0,0 +1,5 @@ +{ + "values": [ + "retold:steel_sword" + ] +} diff --git a/src/main/resources/data/minecraft/worldgen/placed_feature/ore_copper.json b/src/main/resources/data/minecraft/worldgen/placed_feature/ore_copper.json new file mode 100644 index 0000000..60fdf9d --- /dev/null +++ b/src/main/resources/data/minecraft/worldgen/placed_feature/ore_copper.json @@ -0,0 +1,27 @@ +{ + "feature": "minecraft:ore_copper_small", + "placement": [ + { + "type": "minecraft:count", + "count": 6 + }, + { + "type": "minecraft:in_square" + }, + { + "type": "minecraft:height_range", + "height": { + "type": "minecraft:trapezoid", + "max_inclusive": { + "absolute": 112 + }, + "min_inclusive": { + "absolute": -16 + } + } + }, + { + "type": "minecraft:biome" + } + ] +} diff --git a/src/main/resources/data/minecraft/worldgen/placed_feature/ore_copper_large.json b/src/main/resources/data/minecraft/worldgen/placed_feature/ore_copper_large.json new file mode 100644 index 0000000..34c84fa --- /dev/null +++ b/src/main/resources/data/minecraft/worldgen/placed_feature/ore_copper_large.json @@ -0,0 +1,27 @@ +{ + "feature": "minecraft:ore_copper_large", + "placement": [ + { + "type": "minecraft:count", + "count": 6 + }, + { + "type": "minecraft:in_square" + }, + { + "type": "minecraft:height_range", + "height": { + "type": "minecraft:trapezoid", + "max_inclusive": { + "absolute": 112 + }, + "min_inclusive": { + "absolute": -16 + } + } + }, + { + "type": "minecraft:biome" + } + ] +} diff --git a/src/main/resources/data/retold/loot_modifiers/more_leaf_sticks.json b/src/main/resources/data/retold/loot_modifiers/more_leaf_sticks.json new file mode 100644 index 0000000..9d9e5d5 --- /dev/null +++ b/src/main/resources/data/retold/loot_modifiers/more_leaf_sticks.json @@ -0,0 +1,4 @@ +{ + "type": "retold:more_leaf_sticks", + "conditions": [] +} diff --git a/src/main/resources/data/retold/recipe/brick_from_campfire_cooking_clay_ball.json b/src/main/resources/data/retold/recipe/brick_from_campfire_cooking_clay_ball.json new file mode 100644 index 0000000..fd6615e --- /dev/null +++ b/src/main/resources/data/retold/recipe/brick_from_campfire_cooking_clay_ball.json @@ -0,0 +1,9 @@ +{ + "type": "minecraft:campfire_cooking", + "cookingtime": 600, + "experience": 0.3, + "ingredient": "minecraft:clay_ball", + "result": { + "id": "minecraft:brick" + } +} diff --git a/src/main/resources/data/retold/recipe/charcoal_from_smoking_logs.json b/src/main/resources/data/retold/recipe/charcoal_from_smoking_logs.json new file mode 100644 index 0000000..72c96c3 --- /dev/null +++ b/src/main/resources/data/retold/recipe/charcoal_from_smoking_logs.json @@ -0,0 +1,9 @@ +{ + "type": "minecraft:smoking", + "category": "misc", + "experience": 0.15, + "ingredient": "#minecraft:logs_that_burn", + "result": { + "id": "minecraft:charcoal" + } +} diff --git a/src/main/resources/data/retold/recipe/copper_ingot_from_smoking_copper_ore.json b/src/main/resources/data/retold/recipe/copper_ingot_from_smoking_copper_ore.json new file mode 100644 index 0000000..efff39d --- /dev/null +++ b/src/main/resources/data/retold/recipe/copper_ingot_from_smoking_copper_ore.json @@ -0,0 +1,10 @@ +{ + "type": "minecraft:smoking", + "category": "misc", + "experience": 0.7, + "group": "copper_ingot", + "ingredient": "minecraft:copper_ore", + "result": { + "id": "minecraft:copper_ingot" + } +} diff --git a/src/main/resources/data/retold/recipe/copper_ingot_from_smoking_deepslate_copper_ore.json b/src/main/resources/data/retold/recipe/copper_ingot_from_smoking_deepslate_copper_ore.json new file mode 100644 index 0000000..10b2221 --- /dev/null +++ b/src/main/resources/data/retold/recipe/copper_ingot_from_smoking_deepslate_copper_ore.json @@ -0,0 +1,10 @@ +{ + "type": "minecraft:smoking", + "category": "misc", + "experience": 0.7, + "group": "copper_ingot", + "ingredient": "minecraft:deepslate_copper_ore", + "result": { + "id": "minecraft:copper_ingot" + } +} diff --git a/src/main/resources/data/retold/recipe/copper_ingot_from_smoking_raw_copper.json b/src/main/resources/data/retold/recipe/copper_ingot_from_smoking_raw_copper.json new file mode 100644 index 0000000..0d7d068 --- /dev/null +++ b/src/main/resources/data/retold/recipe/copper_ingot_from_smoking_raw_copper.json @@ -0,0 +1,10 @@ +{ + "type": "minecraft:smoking", + "category": "misc", + "experience": 0.7, + "group": "copper_ingot", + "ingredient": "minecraft:raw_copper", + "result": { + "id": "minecraft:copper_ingot" + } +} diff --git a/src/main/resources/data/retold/recipe/flint_multi_tool.json b/src/main/resources/data/retold/recipe/flint_multi_tool.json new file mode 100644 index 0000000..f9acbb1 --- /dev/null +++ b/src/main/resources/data/retold/recipe/flint_multi_tool.json @@ -0,0 +1,15 @@ +{ + "type": "minecraft:crafting_shaped", + "category": "equipment", + "key": { + "F": "minecraft:flint", + "S": "minecraft:stick" + }, + "pattern": [ + "FF", + " S" + ], + "result": { + "id": "retold:flint_multi_tool" + } +} diff --git a/src/main/resources/data/retold/recipe/steel_axe.json b/src/main/resources/data/retold/recipe/steel_axe.json new file mode 100644 index 0000000..7bf90e3 --- /dev/null +++ b/src/main/resources/data/retold/recipe/steel_axe.json @@ -0,0 +1,16 @@ +{ + "type": "minecraft:crafting_shaped", + "category": "equipment", + "key": { + "#": "minecraft:stick", + "X": "#c:ingots/steel" + }, + "pattern": [ + "XX", + "X#", + " #" + ], + "result": { + "id": "retold:steel_axe" + } +} diff --git a/src/main/resources/data/retold/recipe/steel_boots.json b/src/main/resources/data/retold/recipe/steel_boots.json new file mode 100644 index 0000000..e0fa64f --- /dev/null +++ b/src/main/resources/data/retold/recipe/steel_boots.json @@ -0,0 +1,14 @@ +{ + "type": "minecraft:crafting_shaped", + "category": "equipment", + "key": { + "X": "#c:ingots/steel" + }, + "pattern": [ + "X X", + "X X" + ], + "result": { + "id": "retold:steel_boots" + } +} diff --git a/src/main/resources/data/retold/recipe/steel_chestplate.json b/src/main/resources/data/retold/recipe/steel_chestplate.json new file mode 100644 index 0000000..61ba4c0 --- /dev/null +++ b/src/main/resources/data/retold/recipe/steel_chestplate.json @@ -0,0 +1,15 @@ +{ + "type": "minecraft:crafting_shaped", + "category": "equipment", + "key": { + "X": "#c:ingots/steel" + }, + "pattern": [ + "X X", + "XXX", + "XXX" + ], + "result": { + "id": "retold:steel_chestplate" + } +} diff --git a/src/main/resources/data/retold/recipe/steel_helmet.json b/src/main/resources/data/retold/recipe/steel_helmet.json new file mode 100644 index 0000000..dcd2624 --- /dev/null +++ b/src/main/resources/data/retold/recipe/steel_helmet.json @@ -0,0 +1,14 @@ +{ + "type": "minecraft:crafting_shaped", + "category": "equipment", + "key": { + "X": "#c:ingots/steel" + }, + "pattern": [ + "XXX", + "X X" + ], + "result": { + "id": "retold:steel_helmet" + } +} diff --git a/src/main/resources/data/retold/recipe/steel_hoe.json b/src/main/resources/data/retold/recipe/steel_hoe.json new file mode 100644 index 0000000..807554e --- /dev/null +++ b/src/main/resources/data/retold/recipe/steel_hoe.json @@ -0,0 +1,16 @@ +{ + "type": "minecraft:crafting_shaped", + "category": "equipment", + "key": { + "#": "minecraft:stick", + "X": "#c:ingots/steel" + }, + "pattern": [ + "XX", + " #", + " #" + ], + "result": { + "id": "retold:steel_hoe" + } +} diff --git a/src/main/resources/data/retold/recipe/steel_ingot_from_blasting_iron_ingot.json b/src/main/resources/data/retold/recipe/steel_ingot_from_blasting_iron_ingot.json new file mode 100644 index 0000000..75bcc33 --- /dev/null +++ b/src/main/resources/data/retold/recipe/steel_ingot_from_blasting_iron_ingot.json @@ -0,0 +1,11 @@ +{ + "type": "minecraft:blasting", + "category": "misc", + "cookingtime": 100, + "experience": 0.7, + "group": "steel_ingot", + "ingredient": "minecraft:iron_ingot", + "result": { + "id": "retold:steel_ingot" + } +} diff --git a/src/main/resources/data/retold/recipe/steel_leggings.json b/src/main/resources/data/retold/recipe/steel_leggings.json new file mode 100644 index 0000000..a1a5c44 --- /dev/null +++ b/src/main/resources/data/retold/recipe/steel_leggings.json @@ -0,0 +1,15 @@ +{ + "type": "minecraft:crafting_shaped", + "category": "equipment", + "key": { + "X": "#c:ingots/steel" + }, + "pattern": [ + "XXX", + "X X", + "X X" + ], + "result": { + "id": "retold:steel_leggings" + } +} diff --git a/src/main/resources/data/retold/recipe/steel_pickaxe.json b/src/main/resources/data/retold/recipe/steel_pickaxe.json new file mode 100644 index 0000000..119031c --- /dev/null +++ b/src/main/resources/data/retold/recipe/steel_pickaxe.json @@ -0,0 +1,16 @@ +{ + "type": "minecraft:crafting_shaped", + "category": "equipment", + "key": { + "#": "minecraft:stick", + "X": "#c:ingots/steel" + }, + "pattern": [ + "XXX", + " # ", + " # " + ], + "result": { + "id": "retold:steel_pickaxe" + } +} diff --git a/src/main/resources/data/retold/recipe/steel_shovel.json b/src/main/resources/data/retold/recipe/steel_shovel.json new file mode 100644 index 0000000..1efbcc2 --- /dev/null +++ b/src/main/resources/data/retold/recipe/steel_shovel.json @@ -0,0 +1,16 @@ +{ + "type": "minecraft:crafting_shaped", + "category": "equipment", + "key": { + "#": "minecraft:stick", + "X": "#c:ingots/steel" + }, + "pattern": [ + "X", + "#", + "#" + ], + "result": { + "id": "retold:steel_shovel" + } +} diff --git a/src/main/resources/data/retold/recipe/steel_sword.json b/src/main/resources/data/retold/recipe/steel_sword.json new file mode 100644 index 0000000..cf02b2a --- /dev/null +++ b/src/main/resources/data/retold/recipe/steel_sword.json @@ -0,0 +1,16 @@ +{ + "type": "minecraft:crafting_shaped", + "category": "equipment", + "key": { + "#": "minecraft:stick", + "X": "#c:ingots/steel" + }, + "pattern": [ + "X", + "X", + "#" + ], + "result": { + "id": "retold:steel_sword" + } +} diff --git a/src/main/resources/data/retold/tags/block/incorrect_for_flint_multi_tool.json b/src/main/resources/data/retold/tags/block/incorrect_for_flint_multi_tool.json new file mode 100644 index 0000000..f7054f2 --- /dev/null +++ b/src/main/resources/data/retold/tags/block/incorrect_for_flint_multi_tool.json @@ -0,0 +1,6 @@ +{ + "values": [ + "#minecraft:needs_iron_tool", + "#minecraft:needs_diamond_tool" + ] +} diff --git a/src/main/resources/data/retold/tags/block/incorrect_for_steel_tool.json b/src/main/resources/data/retold/tags/block/incorrect_for_steel_tool.json new file mode 100644 index 0000000..8a80961 --- /dev/null +++ b/src/main/resources/data/retold/tags/block/incorrect_for_steel_tool.json @@ -0,0 +1,5 @@ +{ + "values": [ + "#minecraft:needs_diamond_tool" + ] +} diff --git a/src/main/resources/data/retold/tags/block/mineable/flint_multi_tool.json b/src/main/resources/data/retold/tags/block/mineable/flint_multi_tool.json new file mode 100644 index 0000000..330f305 --- /dev/null +++ b/src/main/resources/data/retold/tags/block/mineable/flint_multi_tool.json @@ -0,0 +1,17 @@ +{ + "values": [ + "#minecraft:mineable/axe", + "#minecraft:mineable/shovel", + "minecraft:copper_ore", + "minecraft:sandstone", + "minecraft:chiseled_sandstone", + "minecraft:cut_sandstone", + "minecraft:smooth_sandstone", + "minecraft:red_sandstone", + "minecraft:chiseled_red_sandstone", + "minecraft:cut_red_sandstone", + "minecraft:smooth_red_sandstone", + "minecraft:tuff", + "minecraft:calcite" + ] +} diff --git a/src/main/resources/data/retold/tags/block/steel_tier_blocks.json b/src/main/resources/data/retold/tags/block/steel_tier_blocks.json new file mode 100644 index 0000000..1a06fa4 --- /dev/null +++ b/src/main/resources/data/retold/tags/block/steel_tier_blocks.json @@ -0,0 +1,21 @@ +{ + "values": [ + "minecraft:deepslate", + "minecraft:cobbled_deepslate", + "minecraft:polished_deepslate", + "minecraft:chiseled_deepslate", + "minecraft:deepslate_bricks", + "minecraft:cracked_deepslate_bricks", + "minecraft:deepslate_tiles", + "minecraft:cracked_deepslate_tiles", + "minecraft:reinforced_deepslate", + "minecraft:deepslate_coal_ore", + "minecraft:deepslate_copper_ore", + "minecraft:deepslate_iron_ore", + "minecraft:deepslate_gold_ore", + "minecraft:deepslate_redstone_ore", + "minecraft:deepslate_emerald_ore", + "minecraft:deepslate_lapis_ore", + "minecraft:deepslate_diamond_ore" + ] +} diff --git a/src/main/resources/data/retold/tags/item/flint_multi_tool_repair_materials.json b/src/main/resources/data/retold/tags/item/flint_multi_tool_repair_materials.json new file mode 100644 index 0000000..3489e5c --- /dev/null +++ b/src/main/resources/data/retold/tags/item/flint_multi_tool_repair_materials.json @@ -0,0 +1,5 @@ +{ + "values": [ + "minecraft:flint" + ] +} diff --git a/src/main/resources/data/retold/tags/item/fragile_unenchanted_diamond_armor.json b/src/main/resources/data/retold/tags/item/fragile_unenchanted_diamond_armor.json new file mode 100644 index 0000000..8d80860 --- /dev/null +++ b/src/main/resources/data/retold/tags/item/fragile_unenchanted_diamond_armor.json @@ -0,0 +1,8 @@ +{ + "values": [ + "minecraft:diamond_helmet", + "minecraft:diamond_chestplate", + "minecraft:diamond_leggings", + "minecraft:diamond_boots" + ] +} diff --git a/src/main/resources/data/retold/tags/item/fragile_unenchanted_diamond_tools.json b/src/main/resources/data/retold/tags/item/fragile_unenchanted_diamond_tools.json new file mode 100644 index 0000000..ef05b5c --- /dev/null +++ b/src/main/resources/data/retold/tags/item/fragile_unenchanted_diamond_tools.json @@ -0,0 +1,10 @@ +{ + "values": [ + "minecraft:diamond_sword", + "minecraft:diamond_shovel", + "minecraft:diamond_pickaxe", + "minecraft:diamond_axe", + "minecraft:diamond_hoe", + "minecraft:diamond_spear" + ] +} diff --git a/src/main/resources/data/retold/tags/item/steel_repair_materials.json b/src/main/resources/data/retold/tags/item/steel_repair_materials.json new file mode 100644 index 0000000..3b1db6c --- /dev/null +++ b/src/main/resources/data/retold/tags/item/steel_repair_materials.json @@ -0,0 +1,5 @@ +{ + "values": [ + "#c:ingots/steel" + ] +} diff --git a/src/main/resources/data/retold/villager_teaching/armorer.json b/src/main/resources/data/retold/villager_teaching/armorer.json index 21bde07..082480b 100644 --- a/src/main/resources/data/retold/villager_teaching/armorer.json +++ b/src/main/resources/data/retold/villager_teaching/armorer.json @@ -17,6 +17,22 @@ { "id": "minecraft:iron_boots" }, + { + "id": "retold:steel_helmet", + "emerald_cost": 7 + }, + { + "id": "retold:steel_chestplate", + "emerald_cost": 9 + }, + { + "id": "retold:steel_leggings", + "emerald_cost": 9 + }, + { + "id": "retold:steel_boots", + "emerald_cost": 7 + }, { "id": "minecraft:golden_helmet", "emerald_cost": 5 diff --git a/src/main/resources/data/retold/villager_teaching/toolsmith.json b/src/main/resources/data/retold/villager_teaching/toolsmith.json index c866f39..28fc58d 100644 --- a/src/main/resources/data/retold/villager_teaching/toolsmith.json +++ b/src/main/resources/data/retold/villager_teaching/toolsmith.json @@ -4,28 +4,19 @@ "default_villager_xp_reward": 2, "recipes": [ { - "id": "minecraft:wooden_pickaxe" + "id": "retold:flint_multi_tool" }, { - "id": "minecraft:wooden_axe" + "id": "minecraft:copper_pickaxe" }, { - "id": "minecraft:wooden_shovel" + "id": "minecraft:copper_axe" }, { - "id": "minecraft:wooden_hoe" + "id": "minecraft:copper_shovel" }, { - "id": "minecraft:stone_pickaxe" - }, - { - "id": "minecraft:stone_axe" - }, - { - "id": "minecraft:stone_shovel" - }, - { - "id": "minecraft:stone_hoe" + "id": "minecraft:copper_hoe" }, { "id": "minecraft:iron_pickaxe", @@ -41,6 +32,22 @@ { "id": "minecraft:iron_hoe" }, + { + "id": "retold:steel_pickaxe", + "emerald_cost": 7 + }, + { + "id": "retold:steel_axe", + "emerald_cost": 7 + }, + { + "id": "retold:steel_shovel", + "emerald_cost": 5 + }, + { + "id": "retold:steel_hoe", + "emerald_cost": 5 + }, { "id": "minecraft:golden_pickaxe", "emerald_cost": 4 diff --git a/src/main/resources/data/retold/villager_teaching/weaponsmith.json b/src/main/resources/data/retold/villager_teaching/weaponsmith.json index dd5062f..6b0b09c 100644 --- a/src/main/resources/data/retold/villager_teaching/weaponsmith.json +++ b/src/main/resources/data/retold/villager_teaching/weaponsmith.json @@ -4,15 +4,19 @@ "default_villager_xp_reward": 2, "recipes": [ { - "id": "minecraft:wooden_sword" + "id": "minecraft:copper_sword" }, { - "id": "minecraft:stone_sword" + "id": "minecraft:copper_axe" }, { "id": "minecraft:iron_sword", "emerald_cost": 5 }, + { + "id": "retold:steel_sword", + "emerald_cost": 8 + }, { "id": "minecraft:golden_sword", "emerald_cost": 5 @@ -22,16 +26,14 @@ "emerald_cost": 14, "villager_xp_reward": 5 }, - { - "id": "minecraft:wooden_axe" - }, - { - "id": "minecraft:stone_axe" - }, { "id": "minecraft:iron_axe", "emerald_cost": 5 }, + { + "id": "retold:steel_axe", + "emerald_cost": 8 + }, { "id": "minecraft:golden_axe", "emerald_cost": 5 diff --git a/src/main/resources/retold.mixins.json b/src/main/resources/retold.mixins.json index 5b3e25f..ac13dc6 100644 --- a/src/main/resources/retold.mixins.json +++ b/src/main/resources/retold.mixins.json @@ -4,6 +4,8 @@ "compatibilityLevel": "JAVA_25", "mixins": [ "ServerRecipeBookMixin", + "ItemStackDiamondDurabilityMixin", + "CampfirePlacementMixin", "BadOmenMobEffectMixin", "RaidsMixin", "AdvancementVisibilityEvaluatorMixin", From 3d59fc1319f2d1b800ffe8d930413328d5388e59 Mon Sep 17 00:00:00 2001 From: xefensor Date: Tue, 11 Aug 2026 23:29:15 +0200 Subject: [PATCH 02/11] Enchant animal armor like chestplates --- CHANGELOG.md | 2 + docs/internal/design_implementation_status.md | 2 +- docs/internal/retold_design_risks.md | 2 +- docs/internal/retold_mod_system.md | 6 ++ docs/internal/tool_armor_ore_progression.md | 5 ++ .../RetoldAnimalArmorEnchanting.java | 56 ++++++++++++++ .../enchanting/RetoldEnchantingGameTests.java | 77 +++++++++++++++++++ .../retold/module/RetoldFoundationModule.java | 4 + .../xefensor/retold/registry/RetoldTags.java | 4 + .../tags/item/enchantable/chest_armor.json | 5 ++ .../tags/item/enchantable/durability.json | 5 ++ .../tags/item/enchantable/equippable.json | 5 ++ .../data/retold/tags/item/animal_armor.json | 16 ++++ 13 files changed, 187 insertions(+), 2 deletions(-) create mode 100644 src/main/java/cz/xefensor/retold/enchanting/RetoldAnimalArmorEnchanting.java create mode 100644 src/main/resources/data/minecraft/tags/item/enchantable/chest_armor.json create mode 100644 src/main/resources/data/minecraft/tags/item/enchantable/durability.json create mode 100644 src/main/resources/data/minecraft/tags/item/enchantable/equippable.json create mode 100644 src/main/resources/data/retold/tags/item/animal_armor.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 644addc..0a868e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ Each release should be readable in two passes: - Campfires are now crafted from three Sticks and three Logs without Coal or Flint and begin unlit immediately when placed, without briefly flashing their lit appearance. Using a bare Flint lights one and consumes that Flint in Survival, while Flint and Steel retains its normal durability-based ignition. Clay Balls fire into Bricks on a Campfire; eight Bricks in a ring then craft the Brick Furnace, Retold's renamed Smoker. It keeps food cooking, makes Charcoal from burnable logs, and processes Raw Copper and both Copper ores so players can reach Copper before obtaining Cobblestone for a normal Furnace. - Blast Furnaces now process Iron Ingots directly into Steel Ingots using any ordinary fuel. Steel provides a full Pickaxe, Axe, Shovel, Hoe, Sword, and armor tier between Iron and Diamond. Copper and Iron remain painfully slow on Deepslate-family blocks, while Steel restores full deep-mining speed, harvests deep Diamond Ore, and still leaves Obsidian to Diamond. - Unenchanted Diamond tools and Spears now have only 64 durability, while unenchanted Diamond player armor has leather-like 6x durability. Any enchantment immediately restores full vanilla Diamond durability; removing every enchantment makes the item fragile again. A heavily damaged item stripped beyond that fragile limit retains one final use instead of becoming invalid immediately. +- Wolf Armor and every Horse and Nautilus Armor material can now be enchanted with the same enchantment pool as a Chestplate. Each uses the enchanting value of its own armor material. - The End no longer produces its periodic celestial flashes, temporary brightness pulses, or delayed flash sounds. Retold's generated End sky remains unchanged. - Trial Chambers, Ancient Cities, and the Deep Dark no longer generate in newly explored terrain. Their blocks, items, mobs, biomes, and already-generated content remain available. - Ruined Nether portals no longer generate with loot chests. @@ -26,6 +27,7 @@ Each release should be readable in two passes: - Added the 48-durability Flint Multi-tool and provisional Steel material with data-driven mining, repair, common-ingot, enchantment-family, and armor tags. A global loot modifier supplies additional Sticks from every block in `minecraft:leaves`, and placed-feature overrides reduce both ordinary and Dripstone Copper attempts from sixteen to six per chunk. Exact Wooden/Stone recipes are removed during recipe loading; Armorer, Toolsmith, and Weaponsmith lessons follow the material ladder. Five focused GameTests cover leaf Stick supply, reduced Copper placement across seeded chunk-border samples, the unfueled Campfire recipe and ignition behavior, harvest tiers through Steel, Copper/Deepslate pacing, starter and equipment crafting, Brick Furnace processing, normal Iron-to-Steel blasting, and Furnace availability. - Added tag-driven dynamic Diamond durability through a narrow `ItemStack.getMaxDamage` hook and a named progression policy. Focused coverage verifies fragile tool/armor values, enchantment restoration, removal regression, vanilla-tag preservation, and the over-damaged stripped-item safeguard. +- Added data-driven Chestplate enchantment compatibility and material-matched enchantability components for all twelve vanilla animal armors, with focused registry-backed coverage of their complete supported-enchantment sets. - Added a client-only vanilla-End hook that clears `EndFlashState` after level construction, suppressing all flash rendering, lightmap, and sound paths while preserving the End skybox and leaving other End-style dimensions untouched. - Replaced the vanilla Trial Chamber and Ancient City biome tags with empty tags so the structures remain registered but have no eligible generation biomes. A narrow Overworld biome-builder hook omits the Deep Dark mapping from the default climate preset without unregistering the biome. Added focused GameTest coverage for each boundary. - Added a ruined-portal placement processor that omits template chests without affecting chests or other containers elsewhere, with focused GameTest coverage. diff --git a/docs/internal/design_implementation_status.md b/docs/internal/design_implementation_status.md index 285b70b..5144955 100644 --- a/docs/internal/design_implementation_status.md +++ b/docs/internal/design_implementation_status.md @@ -168,7 +168,7 @@ Largest missing or partial design areas: | Reduced Copper generation | Implemented / needs fresh-world verification | Both `minecraft:ore_copper` and `minecraft:ore_copper_large` now make six placement attempts per chunk instead of sixteen, a 62.5% frequency reduction. Vanilla size-10 ordinary and size-20 Dripstone veins plus their height distribution are preserved. A focused registry-backed GameTest verifies both loaded overrides across three seeded origins spanning a chunk border; several fresh seeds, cave-wall exposure, and existing-versus-new chunk behavior still need natural verification. | | Flint/copper/iron/steel/diamond tool progression | Partial / needs verification | Progression is implemented through Diamond: Wooden/Stone recipes are removed, Copper and Steel geology pacing is active, and unenchanted tagged Diamond tools/Spear use 64 durability while any enchantment restores their vanilla maximum. Removing every enchantment makes them fragile again. Focused tests cover the boundaries and transitions. Netherite/Aenderite equipment and final balance remain incomplete. | | Campfire, Brick Furnace, Furnace, Blast Furnace, and parallel enchanting progression | Partial / needs verification | Campfires use a fuel-free three-Stick/three-Log recipe. Their initial placement state is unlit on both logical sides, avoiding the former client-visible lit-state flash. Bare Flint ignites one and is consumed in Survival; Flint and Steel retains normal durability use. Campfire cooking fires Clay Balls into Bricks, and eight Bricks craft the Smoker-backed Brick Furnace. The Brick and normal Furnace roles are implemented. Per the 2026-08-11 choice, a standard 100-tick blasting recipe converts one Iron Ingot to one Steel Ingot while accepting ordinary Blast Furnace fuels; Charcoal is valid but not mandatory or fixed 1:1. Blast Furnace construction remains vanilla. Enchanting follows the separate deterministic SGA system. | -| Leather/copper/iron/steel/diamond armor progression | Partial / needs verification | Steel has its provisionally balanced four-piece set. Unenchanted Diamond player armor now uses 6x durability (66/96/90/78), while any enchantment restores vanilla 33x durability and removing all enchantments restores fragility. Horse/Nautilus armor are excluded. Later Retold armor tiers remain incomplete. | +| Leather/copper/iron/steel/diamond armor progression | Partial / needs verification | Steel has its provisionally balanced four-piece set. Unenchanted Diamond player armor now uses 6x durability (66/96/90/78), while any enchantment restores vanilla 33x durability and removing all enchantments restores fragility. All twelve Wolf, Horse, and Nautilus Armor items support the exact Chestplate enchantment set and use their material's enchantability value; animal armor remains excluded from Diamond fragility. Later Retold armor tiers remain incomplete. | | Diamond tools weak unless enchanted | Implemented / needs in-game verification | A narrow `ItemStack` hook delegates to `RetoldDiamondDurability`; tagged unenchanted tools use 64 durability and enchanted tools use their vanilla maximum. Stripping a heavily damaged item preserves its damage and leaves one final use rather than an invalid stack. Focused coverage verifies tool and armor enchant/remove transitions and the damaged-item edge case. | | Aenderite ore and refined material | Partial / needs verification | Aenderite generates at diamond-like abundance inside Aender Stone, using mostly 3–4 and 4–8 block veins with rare 8–12 block veins, biased toward island undersides. A Netherite Pickaxe is required; Silk Touch preserves the ore, Fortune applies to Raw Aenderite, and raw material smelts/blasts into an ingot. Tools, armor, blocks, and other ingot uses are intentionally not designed yet. | | Enchanting rework | Partial / needs interaction verification | All 43 currently registered enchantments have unique data-driven `domain + effect + modifier` definitions using the fixed 26-concept SGA vocabulary. Duplicate enchantment/word mappings and unknown concepts are rejected atomically, and the validated catalog is synchronized to clients on join and datapack reload. Known enchantment ids persist per player and each receiving client gets its server-authoritative knowledge snapshot. Completed anvil use teaches only book enchantments that actually increased the result compared with the left input. Unknown mapped tooltip entries show only SGA plus level; known entries retain their readable name and add the SGA word. The developer confirmed tooltip behavior and accepted the current table layout in-game on 2026-08-09. The deterministic table transaction, item-aware known-spell filtering, registered maximum display/limits, green success clearing/highlight, and generic low-note/red-highlight rejection cue are implemented with focused coverage. The newest filtering/feedback interaction and dedicated multiplayer synchronization still need verification. | diff --git a/docs/internal/retold_design_risks.md b/docs/internal/retold_design_risks.md index 1160671..0029489 100644 --- a/docs/internal/retold_design_risks.md +++ b/docs/internal/retold_design_risks.md @@ -33,7 +33,7 @@ | Villages | Container, Farmer-crop, and profession-tended livestock offenses use witnessed vanilla gossip. Sight and village-context checks can be sensitive to walls, crowded settlements, vertical farms, merged double chests, animal transport, automation, and multiplayer timing. | Generated village loot plus Villager-produced quantities are protected; player deposits and ambiguous already-opened existing-world contents are not. Farmer planting/replanting marks persistent crop positions. Shepherds, Leatherworkers, and Butchers claim only animals they successfully feed with two real storage items; player interaction/leashing marks previously unowned livestock as player-associated. Offspring of two owned parents inherit persisted village ownership, while an automatic offspring of a player-associated unowned parent inherits player protection. Witnessed direct Survival kills add `-50`; monsters, environment, Creative, and Spectator do not. Four focused animal tests plus the crop/container groups cover persistence, ownership separation, conservation, offense strengths, witnesses, and exclusions; the latest 50-Villager TPS peak is 6.864 ms/tick. Naturally verify physical storage-to-pen routes, wandering/boat-transport edge cases, full harvest/replant cycles, trade prices, golem reaction, double chests, hoppers, simultaneous players, dedicated servers, and existing worlds before calling the loop fully verified. | | Stage 3 | Raid creation is now gated to Stage 3, but the broader illager behavior may need clearer player-facing feedback later. | Avoid major raid redesign without developer approval. The Stage 2 live creation rejection and Witch/Illager same-raid cooperation are regression-tested; natural Bad Omen preservation, Stage 3 Raid Omen conversion, wave participation, healing, and raid-exit behavior still need in-game verification. Existing raids deliberately continue if an administrative command moves the world back below Stage 3. | | Piglins | Stage 3 piglin/pigman hiring or follower behavior is planned but not implemented. | Needs feature design. | -| Items | The implemented Flint-through-Diamond spine changes first-spawn assumptions, leaf loot, Copper distribution, Campfire ignition, recipes, station use, mining speed, nine Steel equipment items, and the effective maximum durability of existing Diamond equipment. Its provisional balance, fuel economy, compatibility, and reused visuals need validation. Later equipment, mending removal, and combat reworks remain planned. | Focused GameTests cover the material ladder through Steel, six-attempt ordinary/large Copper placement across seeded chunk-border origins while retaining vanilla vein sizes, the 20% supplemental 1–2 Stick leaf roll and its Fortune/shears/Silk Touch boundaries, the fuel-free Campfire recipe, the real unlit initial placement-state hook, consumable bare-Flint ignition, durable Flint and Steel ignition, Clay-to-Brick campfire cooking, and the eight-Brick furnace boundary, plus dynamic Diamond tool/armor durability, enchant/remove transitions, and the heavily damaged stripped-item edge case. The Copper override affects only newly generated chunks; naturally inspect multiple fresh seeds, ordinary and Dripstone caves, cave-wall exposure, chunk borders, early acquisition time, and datapack/worldgen-mod compatibility before further tuning. Visually verify that Campfire placement no longer flashes lit on the client, plus cooking four Clay items, water/extinguishing, Creative consumption exemption, automation, recipe-book presentation, multiplayer, and compatibility with Campfire/recipe mods. Also verify leaf breaking and decay, explosions, non-Oak and modded tagged leaves, first-spawn Stick pacing, and interaction with datapacks or other global loot modifiers before final tuning. Option 2 means any enchantment grants full vanilla Diamond durability, while removing all enchantments restores fragility; tagged tools/Spear use 64 unenchanted durability and player armor uses 6x. Existing unenchanted Diamond gear changes automatically after update. Naturally test crafting, table/anvil/loot/command enchantments, Grindstone removal, durability bars/tooltips, break timing, repair/Mending interactions, deaths/containers, multiple equipment types, multiplayer, dedicated servers, and existing worlds. A stripped over-cap item deliberately retains one final use. Also measure Steel's ordinary-fuel economy and naturally verify its recipes/stats/repairs/enchanting/trims and reused Iron visuals. Aenderite still provides only an ore/raw/ingot foundation. | +| Items | The implemented Flint-through-Diamond spine changes first-spawn assumptions, leaf loot, Copper distribution, Campfire ignition, recipes, station use, mining speed, nine Steel equipment items, animal-armor enchanting, and the effective maximum durability of existing Diamond equipment. Its provisional balance, fuel economy, compatibility, and reused visuals need validation. Later equipment, mending removal, and combat reworks remain planned. | Focused GameTests cover the material ladder through Steel, six-attempt ordinary/large Copper placement across seeded chunk-border origins while retaining vanilla vein sizes, the 20% supplemental 1–2 Stick leaf roll and its Fortune/shears/Silk Touch boundaries, the fuel-free Campfire recipe, the real unlit initial placement-state hook, consumable bare-Flint ignition, durable Flint and Steel ignition, Clay-to-Brick campfire cooking, and the eight-Brick furnace boundary, plus dynamic Diamond tool/armor durability, enchant/remove transitions, the heavily damaged stripped-item edge case, and all twelve animal armors' exact Chestplate enchantment compatibility. The Copper override affects only newly generated chunks; naturally inspect multiple fresh seeds, ordinary and Dripstone caves, cave-wall exposure, chunk borders, early acquisition time, and datapack/worldgen-mod compatibility before further tuning. Visually verify that Campfire placement no longer flashes lit on the client, plus cooking four Clay items, water/extinguishing, Creative consumption exemption, automation, recipe-book presentation, multiplayer, and compatibility with Campfire/recipe mods. Also verify leaf breaking and decay, explosions, non-Oak and modded tagged leaves, first-spawn Stick pacing, and interaction with datapacks or other global loot modifiers before final tuning. Option 2 means any enchantment grants full vanilla Diamond durability, while removing all enchantments restores fragility; tagged tools/Spear use 64 unenchanted durability and player armor uses 6x. Existing unenchanted Diamond gear changes automatically after update. Naturally test crafting, table/anvil/loot/command enchantments, Grindstone removal, durability bars/tooltips, break timing, repair/Mending interactions, deaths/containers, multiple equipment types, multiplayer, dedicated servers, and existing worlds. A stripped over-cap item deliberately retains one final use. Naturally verify Protection-family mitigation, Thorns retaliation, curses, enchanting-table/anvil/SGA presentation, and Unbreaking/Mending behavior on equipped Wolf, Horse, and Nautilus Armor. Also measure Steel's ordinary-fuel economy and naturally verify its recipes/stats/repairs/enchanting/trims and reused Iron visuals. Aenderite still provides only an ore/raw/ingot foundation. | | Environment | Death drops should despawn much later than vanilla, not never. | No implementation confirmed. | | Beds | Beds should not skip night; valid daytime bed rest is allowed when night skipping is disabled. | Healing behavior not confirmed implemented. | | Nether | Nether portal spread is planned as energy drain. | Needs bounded implementation design. | diff --git a/docs/internal/retold_mod_system.md b/docs/internal/retold_mod_system.md index 23a76ef..6db429d 100644 --- a/docs/internal/retold_mod_system.md +++ b/docs/internal/retold_mod_system.md @@ -163,6 +163,12 @@ enchantments restores fragility. Raw damage is read directly from the component re-enter itself; an over-cap stripped item receives an effective `damage + 1` maximum and one final use. +`RetoldAnimalArmorEnchanting` adds material-matched enchantability components to Wolf Armor and +every Horse and Nautilus Armor variant during default-component initialization. The +`retold:animal_armor` item tag is included in the vanilla Chestplate, durability, and equippable +enchantment families, giving those twelve items the same supported enchantment set as a player +Chestplate without including them in Retold's fragile Diamond player-armor tag. + ## World Stage System World stages are the backbone of Retold progression. diff --git a/docs/internal/tool_armor_ore_progression.md b/docs/internal/tool_armor_ore_progression.md index 9f5356e..73367ec 100644 --- a/docs/internal/tool_armor_ore_progression.md +++ b/docs/internal/tool_armor_ore_progression.md @@ -491,6 +491,11 @@ Copper and Steel receive full armor sets. Diamond armor follows the same low-unenchanted-durability rule as Diamond tools. +Wolf Armor and all Horse and Nautilus Armor materials support the same enchantment compatibility +set as a player Chestplate. Each animal armor uses its matching material's enchantability value; +Wolf Armor uses the Armadillo Scute material value. Animal armor remains excluded from Diamond's +fragile-until-enchanted durability rule. + Netherite upgrades Diamond gear. Aenderite armor behavior remains TBD and should be designed around Aender-specific utility rather than only defense inflation. diff --git a/src/main/java/cz/xefensor/retold/enchanting/RetoldAnimalArmorEnchanting.java b/src/main/java/cz/xefensor/retold/enchanting/RetoldAnimalArmorEnchanting.java new file mode 100644 index 0000000..402f795 --- /dev/null +++ b/src/main/java/cz/xefensor/retold/enchanting/RetoldAnimalArmorEnchanting.java @@ -0,0 +1,56 @@ +package cz.xefensor.retold.enchanting; + +import net.minecraft.core.component.DataComponents; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.enchantment.Enchantable; +import net.minecraft.world.item.equipment.ArmorMaterial; +import net.minecraft.world.item.equipment.ArmorMaterials; +import net.neoforged.neoforge.event.ModifyDefaultComponentsEvent; + +import java.util.List; + +/** Gives vanilla animal armor the enchantability of its matching armor material. */ +public final class RetoldAnimalArmorEnchanting { + private static final List ANIMAL_ARMOR = List.of( + armor(Items.WOLF_ARMOR, ArmorMaterials.ARMADILLO_SCUTE), + armor(Items.LEATHER_HORSE_ARMOR, ArmorMaterials.LEATHER), + armor(Items.COPPER_HORSE_ARMOR, ArmorMaterials.COPPER), + armor(Items.IRON_HORSE_ARMOR, ArmorMaterials.IRON), + armor(Items.GOLDEN_HORSE_ARMOR, ArmorMaterials.GOLD), + armor(Items.DIAMOND_HORSE_ARMOR, ArmorMaterials.DIAMOND), + armor(Items.NETHERITE_HORSE_ARMOR, ArmorMaterials.NETHERITE), + armor(Items.COPPER_NAUTILUS_ARMOR, ArmorMaterials.COPPER), + armor(Items.IRON_NAUTILUS_ARMOR, ArmorMaterials.IRON), + armor(Items.GOLDEN_NAUTILUS_ARMOR, ArmorMaterials.GOLD), + armor(Items.DIAMOND_NAUTILUS_ARMOR, ArmorMaterials.DIAMOND), + armor(Items.NETHERITE_NAUTILUS_ARMOR, ArmorMaterials.NETHERITE) + ); + + private RetoldAnimalArmorEnchanting() { + } + + public static void modifyDefaultComponents( + ModifyDefaultComponentsEvent event + ) { + for (AnimalArmorDefinition definition : ANIMAL_ARMOR) { + event.modify( + definition.item(), + (components, context, item) -> components.set( + DataComponents.ENCHANTABLE, + new Enchantable(definition.enchantability()) + ) + ); + } + } + + private static AnimalArmorDefinition armor( + Item item, + ArmorMaterial material + ) { + return new AnimalArmorDefinition(item, material.enchantmentValue()); + } + + private record AnimalArmorDefinition(Item item, int enchantability) { + } +} diff --git a/src/main/java/cz/xefensor/retold/enchanting/RetoldEnchantingGameTests.java b/src/main/java/cz/xefensor/retold/enchanting/RetoldEnchantingGameTests.java index ac90067..a64c693 100644 --- a/src/main/java/cz/xefensor/retold/enchanting/RetoldEnchantingGameTests.java +++ b/src/main/java/cz/xefensor/retold/enchanting/RetoldEnchantingGameTests.java @@ -8,9 +8,11 @@ import cz.xefensor.retold.network.RetoldEnchantmentCatalogSyncPayload; import cz.xefensor.retold.network.RetoldEnchantingCastPayload; import cz.xefensor.retold.network.RetoldEnchantingCastResultPayload; +import cz.xefensor.retold.registry.RetoldTags; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import net.minecraft.core.Holder; +import net.minecraft.core.component.DataComponents; import net.minecraft.core.registries.Registries; import net.minecraft.gametest.framework.BuiltinTestFunctions; import net.minecraft.gametest.framework.FunctionGameTestInstance; @@ -23,18 +25,22 @@ import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.inventory.AnvilMenu; import net.minecraft.world.inventory.EnchantmentMenu; +import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.item.enchantment.Enchantment; import net.minecraft.world.item.enchantment.EnchantmentHelper; import net.minecraft.world.item.enchantment.Enchantments; +import net.minecraft.world.item.enchantment.Enchantable; import net.minecraft.world.level.GameType; import net.neoforged.neoforge.event.RegisterGameTestsEvent; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.function.Consumer; +import java.util.stream.Collectors; public final class RetoldEnchantingGameTests { private static final Identifier EMPTY_STRUCTURE = @@ -112,6 +118,13 @@ public static void register( RetoldEnchantingGameTests::knownEnchantingOptionsFollowInsertedItem ) ); + event.registerTest( + id("animal_armor_supports_chestplate_enchantments"), + new InlineGameTest( + testData, + RetoldEnchantingGameTests::animalArmorSupportsChestplateEnchantments + ) + ); } private static void anvilTeachesOnlyTransferredEnchantments(GameTestHelper helper) { @@ -704,6 +717,70 @@ private static void knownEnchantingOptionsFollowInsertedItem( helper.succeed(); } + private static void animalArmorSupportsChestplateEnchantments( + GameTestHelper helper + ) { + Map animalArmorEnchantability = Map.ofEntries( + Map.entry(Items.WOLF_ARMOR, 10), + Map.entry(Items.LEATHER_HORSE_ARMOR, 15), + Map.entry(Items.COPPER_HORSE_ARMOR, 8), + Map.entry(Items.IRON_HORSE_ARMOR, 9), + Map.entry(Items.GOLDEN_HORSE_ARMOR, 25), + Map.entry(Items.DIAMOND_HORSE_ARMOR, 10), + Map.entry(Items.NETHERITE_HORSE_ARMOR, 15), + Map.entry(Items.COPPER_NAUTILUS_ARMOR, 8), + Map.entry(Items.IRON_NAUTILUS_ARMOR, 9), + Map.entry(Items.GOLDEN_NAUTILUS_ARMOR, 25), + Map.entry(Items.DIAMOND_NAUTILUS_ARMOR, 10), + Map.entry(Items.NETHERITE_NAUTILUS_ARMOR, 15) + ); + Set chestplateEnchantments = supportedEnchantments( + helper, + new ItemStack(Items.DIAMOND_CHESTPLATE) + ); + + for (Map.Entry entry + : animalArmorEnchantability.entrySet()) { + ItemStack animalArmor = new ItemStack(entry.getKey()); + helper.assertTrue( + animalArmor.is(RetoldTags.ANIMAL_ARMOR), + animalArmor.getItem() + " must be tagged as animal armor" + ); + helper.assertValueEqual( + animalArmor.get(DataComponents.ENCHANTABLE), + new Enchantable(entry.getValue()), + animalArmor.getItem() + + " must use its armor material's enchantability" + ); + helper.assertTrue( + animalArmor.isEnchantable(), + animalArmor.getItem() + + " must be accepted by enchanting interfaces" + ); + helper.assertValueEqual( + supportedEnchantments(helper, animalArmor), + chestplateEnchantments, + animalArmor.getItem() + + " must support exactly the Diamond Chestplate enchantments" + ); + } + + helper.succeed(); + } + + private static Set supportedEnchantments( + GameTestHelper helper, + ItemStack stack + ) { + return helper.getLevel() + .registryAccess() + .lookupOrThrow(Registries.ENCHANTMENT) + .listElements() + .filter(stack::supportsEnchantment) + .map(enchantment -> enchantment.key().identifier()) + .collect(Collectors.toUnmodifiableSet()); + } + private static boolean containsEnchantment( List definitions, Identifier enchantment diff --git a/src/main/java/cz/xefensor/retold/module/RetoldFoundationModule.java b/src/main/java/cz/xefensor/retold/module/RetoldFoundationModule.java index 41d95e9..ebaca9d 100644 --- a/src/main/java/cz/xefensor/retold/module/RetoldFoundationModule.java +++ b/src/main/java/cz/xefensor/retold/module/RetoldFoundationModule.java @@ -2,6 +2,7 @@ import cz.xefensor.retold.client.RetoldClientEvents; import cz.xefensor.retold.enchanting.RetoldAnvilLearningEvents; +import cz.xefensor.retold.enchanting.RetoldAnimalArmorEnchanting; import cz.xefensor.retold.enchanting.RetoldEnchantmentCatalogSyncEvents; import cz.xefensor.retold.enchanting.RetoldEnchantmentReloadListener; import cz.xefensor.retold.event.RetoldCommandEvents; @@ -36,6 +37,9 @@ public static void registerModBus(IEventBus modEventBus) { RetoldGameRules.register(modEventBus); modEventBus.addListener(RetoldNetworking::registerPayloads); + modEventBus.addListener( + RetoldAnimalArmorEnchanting::modifyDefaultComponents + ); modEventBus.addListener(RetoldEntityEvents::registerAttributes); modEventBus.addListener(RetoldEntityEvents::registerSpawnPlacements); modEventBus.addListener(RetoldGameTests::register); diff --git a/src/main/java/cz/xefensor/retold/registry/RetoldTags.java b/src/main/java/cz/xefensor/retold/registry/RetoldTags.java index ba545e7..801b003 100644 --- a/src/main/java/cz/xefensor/retold/registry/RetoldTags.java +++ b/src/main/java/cz/xefensor/retold/registry/RetoldTags.java @@ -13,6 +13,10 @@ public final class RetoldTags { Registries.ITEM, Identifier.fromNamespaceAndPath(Retold.MODID, "torch_igniters") ); + public static final TagKey ANIMAL_ARMOR = TagKey.create( + Registries.ITEM, + Identifier.fromNamespaceAndPath(Retold.MODID, "animal_armor") + ); public static final TagKey FLINT_MULTI_TOOL_REPAIR_MATERIALS = TagKey.create( Registries.ITEM, diff --git a/src/main/resources/data/minecraft/tags/item/enchantable/chest_armor.json b/src/main/resources/data/minecraft/tags/item/enchantable/chest_armor.json new file mode 100644 index 0000000..200dc90 --- /dev/null +++ b/src/main/resources/data/minecraft/tags/item/enchantable/chest_armor.json @@ -0,0 +1,5 @@ +{ + "values": [ + "#retold:animal_armor" + ] +} diff --git a/src/main/resources/data/minecraft/tags/item/enchantable/durability.json b/src/main/resources/data/minecraft/tags/item/enchantable/durability.json new file mode 100644 index 0000000..200dc90 --- /dev/null +++ b/src/main/resources/data/minecraft/tags/item/enchantable/durability.json @@ -0,0 +1,5 @@ +{ + "values": [ + "#retold:animal_armor" + ] +} diff --git a/src/main/resources/data/minecraft/tags/item/enchantable/equippable.json b/src/main/resources/data/minecraft/tags/item/enchantable/equippable.json new file mode 100644 index 0000000..200dc90 --- /dev/null +++ b/src/main/resources/data/minecraft/tags/item/enchantable/equippable.json @@ -0,0 +1,5 @@ +{ + "values": [ + "#retold:animal_armor" + ] +} diff --git a/src/main/resources/data/retold/tags/item/animal_armor.json b/src/main/resources/data/retold/tags/item/animal_armor.json new file mode 100644 index 0000000..871194c --- /dev/null +++ b/src/main/resources/data/retold/tags/item/animal_armor.json @@ -0,0 +1,16 @@ +{ + "values": [ + "minecraft:wolf_armor", + "minecraft:leather_horse_armor", + "minecraft:copper_horse_armor", + "minecraft:iron_horse_armor", + "minecraft:golden_horse_armor", + "minecraft:diamond_horse_armor", + "minecraft:netherite_horse_armor", + "minecraft:copper_nautilus_armor", + "minecraft:iron_nautilus_armor", + "minecraft:golden_nautilus_armor", + "minecraft:diamond_nautilus_armor", + "minecraft:netherite_nautilus_armor" + ] +} From 02512daea9e3393e3387d915e5cbae71718c968b Mon Sep 17 00:00:00 2001 From: xefensor Date: Tue, 11 Aug 2026 23:53:48 +0200 Subject: [PATCH 03/11] Apply enchantment effects to animal armor --- CHANGELOG.md | 4 +- docs/internal/design_implementation_status.md | 2 +- docs/internal/retold_design_risks.md | 2 +- docs/internal/retold_mod_system.md | 9 +- docs/internal/tool_armor_ore_progression.md | 8 +- .../RetoldAnimalArmorEnchanting.java | 35 +- .../enchanting/RetoldEnchantingGameTests.java | 299 ++++++++++++++++++ .../retold/module/RetoldFoundationModule.java | 1 + 8 files changed, 353 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a868e5..18e18b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,7 @@ Each release should be readable in two passes: - Campfires are now crafted from three Sticks and three Logs without Coal or Flint and begin unlit immediately when placed, without briefly flashing their lit appearance. Using a bare Flint lights one and consumes that Flint in Survival, while Flint and Steel retains its normal durability-based ignition. Clay Balls fire into Bricks on a Campfire; eight Bricks in a ring then craft the Brick Furnace, Retold's renamed Smoker. It keeps food cooking, makes Charcoal from burnable logs, and processes Raw Copper and both Copper ores so players can reach Copper before obtaining Cobblestone for a normal Furnace. - Blast Furnaces now process Iron Ingots directly into Steel Ingots using any ordinary fuel. Steel provides a full Pickaxe, Axe, Shovel, Hoe, Sword, and armor tier between Iron and Diamond. Copper and Iron remain painfully slow on Deepslate-family blocks, while Steel restores full deep-mining speed, harvests deep Diamond Ore, and still leaves Obsidian to Diamond. - Unenchanted Diamond tools and Spears now have only 64 durability, while unenchanted Diamond player armor has leather-like 6x durability. Any enchantment immediately restores full vanilla Diamond durability; removing every enchantment makes the item fragile again. A heavily damaged item stripped beyond that fragile limit retains one final use instead of becoming invalid immediately. -- Wolf Armor and every Horse and Nautilus Armor material can now be enchanted with the same enchantment pool as a Chestplate. Each uses the enchanting value of its own armor material. +- Wolf Armor and every Horse and Nautilus Armor material can now be enchanted with the same enchantment pool as a Chestplate. Each uses the enchanting value of its own armor material. Protection enchantments now affect damage absorbed by Wolf Armor as well as ordinary animal health damage; Fire Protection also retains its normal shorter-burning effect. - The End no longer produces its periodic celestial flashes, temporary brightness pulses, or delayed flash sounds. Retold's generated End sky remains unchanged. - Trial Chambers, Ancient Cities, and the Deep Dark no longer generate in newly explored terrain. Their blocks, items, mobs, biomes, and already-generated content remain available. - Ruined Nether portals no longer generate with loot chests. @@ -27,7 +27,7 @@ Each release should be readable in two passes: - Added the 48-durability Flint Multi-tool and provisional Steel material with data-driven mining, repair, common-ingot, enchantment-family, and armor tags. A global loot modifier supplies additional Sticks from every block in `minecraft:leaves`, and placed-feature overrides reduce both ordinary and Dripstone Copper attempts from sixteen to six per chunk. Exact Wooden/Stone recipes are removed during recipe loading; Armorer, Toolsmith, and Weaponsmith lessons follow the material ladder. Five focused GameTests cover leaf Stick supply, reduced Copper placement across seeded chunk-border samples, the unfueled Campfire recipe and ignition behavior, harvest tiers through Steel, Copper/Deepslate pacing, starter and equipment crafting, Brick Furnace processing, normal Iron-to-Steel blasting, and Furnace availability. - Added tag-driven dynamic Diamond durability through a narrow `ItemStack.getMaxDamage` hook and a named progression policy. Focused coverage verifies fragile tool/armor values, enchantment restoration, removal regression, vanilla-tag preservation, and the over-damaged stripped-item safeguard. -- Added data-driven Chestplate enchantment compatibility and material-matched enchantability components for all twelve vanilla animal armors, with focused registry-backed coverage of their complete supported-enchantment sets. +- Added data-driven Chestplate enchantment compatibility and material-matched enchantability components for all twelve vanilla animal armors. A Wolf-specific incoming-damage bridge applies vanilla enchantment protection before Wolf Armor's special durability-absorption path bypasses ordinary living-entity mitigation. Focused coverage verifies every supported-enchantment set plus equipped Protection-family mitigation, Fire Protection burn duration, Thorns, Unbreaking, Mending, Binding, and Vanishing behavior across Wolf, Horse, and Nautilus armor paths. - Added a client-only vanilla-End hook that clears `EndFlashState` after level construction, suppressing all flash rendering, lightmap, and sound paths while preserving the End skybox and leaving other End-style dimensions untouched. - Replaced the vanilla Trial Chamber and Ancient City biome tags with empty tags so the structures remain registered but have no eligible generation biomes. A narrow Overworld biome-builder hook omits the Deep Dark mapping from the default climate preset without unregistering the biome. Added focused GameTest coverage for each boundary. - Added a ruined-portal placement processor that omits template chests without affecting chests or other containers elsewhere, with focused GameTest coverage. diff --git a/docs/internal/design_implementation_status.md b/docs/internal/design_implementation_status.md index 5144955..3636760 100644 --- a/docs/internal/design_implementation_status.md +++ b/docs/internal/design_implementation_status.md @@ -168,7 +168,7 @@ Largest missing or partial design areas: | Reduced Copper generation | Implemented / needs fresh-world verification | Both `minecraft:ore_copper` and `minecraft:ore_copper_large` now make six placement attempts per chunk instead of sixteen, a 62.5% frequency reduction. Vanilla size-10 ordinary and size-20 Dripstone veins plus their height distribution are preserved. A focused registry-backed GameTest verifies both loaded overrides across three seeded origins spanning a chunk border; several fresh seeds, cave-wall exposure, and existing-versus-new chunk behavior still need natural verification. | | Flint/copper/iron/steel/diamond tool progression | Partial / needs verification | Progression is implemented through Diamond: Wooden/Stone recipes are removed, Copper and Steel geology pacing is active, and unenchanted tagged Diamond tools/Spear use 64 durability while any enchantment restores their vanilla maximum. Removing every enchantment makes them fragile again. Focused tests cover the boundaries and transitions. Netherite/Aenderite equipment and final balance remain incomplete. | | Campfire, Brick Furnace, Furnace, Blast Furnace, and parallel enchanting progression | Partial / needs verification | Campfires use a fuel-free three-Stick/three-Log recipe. Their initial placement state is unlit on both logical sides, avoiding the former client-visible lit-state flash. Bare Flint ignites one and is consumed in Survival; Flint and Steel retains normal durability use. Campfire cooking fires Clay Balls into Bricks, and eight Bricks craft the Smoker-backed Brick Furnace. The Brick and normal Furnace roles are implemented. Per the 2026-08-11 choice, a standard 100-tick blasting recipe converts one Iron Ingot to one Steel Ingot while accepting ordinary Blast Furnace fuels; Charcoal is valid but not mandatory or fixed 1:1. Blast Furnace construction remains vanilla. Enchanting follows the separate deterministic SGA system. | -| Leather/copper/iron/steel/diamond armor progression | Partial / needs verification | Steel has its provisionally balanced four-piece set. Unenchanted Diamond player armor now uses 6x durability (66/96/90/78), while any enchantment restores vanilla 33x durability and removing all enchantments restores fragility. All twelve Wolf, Horse, and Nautilus Armor items support the exact Chestplate enchantment set and use their material's enchantability value; animal armor remains excluded from Diamond fragility. Later Retold armor tiers remain incomplete. | +| Leather/copper/iron/steel/diamond armor progression | Partial / needs verification | Steel has its provisionally balanced four-piece set. Unenchanted Diamond player armor now uses 6x durability (66/96/90/78), while any enchantment restores vanilla 33x durability and removing all enchantments restores fragility. All twelve Wolf, Horse, and Nautilus Armor items support the exact Chestplate enchantment set and use their material's enchantability value; animal armor remains excluded from Diamond fragility. A focused equipped-animal test covers Protection-family mitigation, Fire Protection burn duration, Thorns, Unbreaking, Mending, Binding, and Vanishing paths. Retold bridges protection into Wolf Armor's special absorbed-durability path; Horse and Nautilus armor use vanilla health mitigation and remain indestructible. Later Retold armor tiers remain incomplete. | | Diamond tools weak unless enchanted | Implemented / needs in-game verification | A narrow `ItemStack` hook delegates to `RetoldDiamondDurability`; tagged unenchanted tools use 64 durability and enchanted tools use their vanilla maximum. Stripping a heavily damaged item preserves its damage and leaves one final use rather than an invalid stack. Focused coverage verifies tool and armor enchant/remove transitions and the damaged-item edge case. | | Aenderite ore and refined material | Partial / needs verification | Aenderite generates at diamond-like abundance inside Aender Stone, using mostly 3–4 and 4–8 block veins with rare 8–12 block veins, biased toward island undersides. A Netherite Pickaxe is required; Silk Touch preserves the ore, Fortune applies to Raw Aenderite, and raw material smelts/blasts into an ingot. Tools, armor, blocks, and other ingot uses are intentionally not designed yet. | | Enchanting rework | Partial / needs interaction verification | All 43 currently registered enchantments have unique data-driven `domain + effect + modifier` definitions using the fixed 26-concept SGA vocabulary. Duplicate enchantment/word mappings and unknown concepts are rejected atomically, and the validated catalog is synchronized to clients on join and datapack reload. Known enchantment ids persist per player and each receiving client gets its server-authoritative knowledge snapshot. Completed anvil use teaches only book enchantments that actually increased the result compared with the left input. Unknown mapped tooltip entries show only SGA plus level; known entries retain their readable name and add the SGA word. The developer confirmed tooltip behavior and accepted the current table layout in-game on 2026-08-09. The deterministic table transaction, item-aware known-spell filtering, registered maximum display/limits, green success clearing/highlight, and generic low-note/red-highlight rejection cue are implemented with focused coverage. The newest filtering/feedback interaction and dedicated multiplayer synchronization still need verification. | diff --git a/docs/internal/retold_design_risks.md b/docs/internal/retold_design_risks.md index 0029489..96a1df5 100644 --- a/docs/internal/retold_design_risks.md +++ b/docs/internal/retold_design_risks.md @@ -33,7 +33,7 @@ | Villages | Container, Farmer-crop, and profession-tended livestock offenses use witnessed vanilla gossip. Sight and village-context checks can be sensitive to walls, crowded settlements, vertical farms, merged double chests, animal transport, automation, and multiplayer timing. | Generated village loot plus Villager-produced quantities are protected; player deposits and ambiguous already-opened existing-world contents are not. Farmer planting/replanting marks persistent crop positions. Shepherds, Leatherworkers, and Butchers claim only animals they successfully feed with two real storage items; player interaction/leashing marks previously unowned livestock as player-associated. Offspring of two owned parents inherit persisted village ownership, while an automatic offspring of a player-associated unowned parent inherits player protection. Witnessed direct Survival kills add `-50`; monsters, environment, Creative, and Spectator do not. Four focused animal tests plus the crop/container groups cover persistence, ownership separation, conservation, offense strengths, witnesses, and exclusions; the latest 50-Villager TPS peak is 6.864 ms/tick. Naturally verify physical storage-to-pen routes, wandering/boat-transport edge cases, full harvest/replant cycles, trade prices, golem reaction, double chests, hoppers, simultaneous players, dedicated servers, and existing worlds before calling the loop fully verified. | | Stage 3 | Raid creation is now gated to Stage 3, but the broader illager behavior may need clearer player-facing feedback later. | Avoid major raid redesign without developer approval. The Stage 2 live creation rejection and Witch/Illager same-raid cooperation are regression-tested; natural Bad Omen preservation, Stage 3 Raid Omen conversion, wave participation, healing, and raid-exit behavior still need in-game verification. Existing raids deliberately continue if an administrative command moves the world back below Stage 3. | | Piglins | Stage 3 piglin/pigman hiring or follower behavior is planned but not implemented. | Needs feature design. | -| Items | The implemented Flint-through-Diamond spine changes first-spawn assumptions, leaf loot, Copper distribution, Campfire ignition, recipes, station use, mining speed, nine Steel equipment items, animal-armor enchanting, and the effective maximum durability of existing Diamond equipment. Its provisional balance, fuel economy, compatibility, and reused visuals need validation. Later equipment, mending removal, and combat reworks remain planned. | Focused GameTests cover the material ladder through Steel, six-attempt ordinary/large Copper placement across seeded chunk-border origins while retaining vanilla vein sizes, the 20% supplemental 1–2 Stick leaf roll and its Fortune/shears/Silk Touch boundaries, the fuel-free Campfire recipe, the real unlit initial placement-state hook, consumable bare-Flint ignition, durable Flint and Steel ignition, Clay-to-Brick campfire cooking, and the eight-Brick furnace boundary, plus dynamic Diamond tool/armor durability, enchant/remove transitions, the heavily damaged stripped-item edge case, and all twelve animal armors' exact Chestplate enchantment compatibility. The Copper override affects only newly generated chunks; naturally inspect multiple fresh seeds, ordinary and Dripstone caves, cave-wall exposure, chunk borders, early acquisition time, and datapack/worldgen-mod compatibility before further tuning. Visually verify that Campfire placement no longer flashes lit on the client, plus cooking four Clay items, water/extinguishing, Creative consumption exemption, automation, recipe-book presentation, multiplayer, and compatibility with Campfire/recipe mods. Also verify leaf breaking and decay, explosions, non-Oak and modded tagged leaves, first-spawn Stick pacing, and interaction with datapacks or other global loot modifiers before final tuning. Option 2 means any enchantment grants full vanilla Diamond durability, while removing all enchantments restores fragility; tagged tools/Spear use 64 unenchanted durability and player armor uses 6x. Existing unenchanted Diamond gear changes automatically after update. Naturally test crafting, table/anvil/loot/command enchantments, Grindstone removal, durability bars/tooltips, break timing, repair/Mending interactions, deaths/containers, multiple equipment types, multiplayer, dedicated servers, and existing worlds. A stripped over-cap item deliberately retains one final use. Naturally verify Protection-family mitigation, Thorns retaliation, curses, enchanting-table/anvil/SGA presentation, and Unbreaking/Mending behavior on equipped Wolf, Horse, and Nautilus Armor. Also measure Steel's ordinary-fuel economy and naturally verify its recipes/stats/repairs/enchanting/trims and reused Iron visuals. Aenderite still provides only an ore/raw/ingot foundation. | +| Items | The implemented Flint-through-Diamond spine changes first-spawn assumptions, leaf loot, Copper distribution, Campfire ignition, recipes, station use, mining speed, nine Steel equipment items, animal-armor enchanting, and the effective maximum durability of existing Diamond equipment. Its provisional balance, fuel economy, compatibility, and reused visuals need validation. Later equipment, mending removal, and combat reworks remain planned. | Focused GameTests cover the material ladder through Steel, six-attempt ordinary/large Copper placement across seeded chunk-border origins while retaining vanilla vein sizes, the 20% supplemental 1–2 Stick leaf roll and its Fortune/shears/Silk Touch boundaries, the fuel-free Campfire recipe, the real unlit initial placement-state hook, consumable bare-Flint ignition, durable Flint and Steel ignition, Clay-to-Brick campfire cooking, and the eight-Brick furnace boundary, plus dynamic Diamond tool/armor durability, enchant/remove transitions, the heavily damaged stripped-item edge case, all twelve animal armors' exact Chestplate enchantment compatibility, and equipped-animal Protection-family, fire-duration, Thorns, durability, Mending, and curse paths. Wolf Armor's special absorption path now applies vanilla enchantment protection before converting damage into durability loss; Fire Protection remains damage/duration reduction rather than immunity, and indestructible Horse/Nautilus armor gives durability-only enchantments no durability pool to change. The Copper override affects only newly generated chunks; naturally inspect multiple fresh seeds, ordinary and Dripstone caves, cave-wall exposure, chunk borders, early acquisition time, and datapack/worldgen-mod compatibility before further tuning. Visually verify that Campfire placement no longer flashes lit on the client, plus cooking four Clay items, water/extinguishing, Creative consumption exemption, automation, recipe-book presentation, multiplayer, and compatibility with Campfire/recipe mods. Also verify leaf breaking and decay, explosions, non-Oak and modded tagged leaves, first-spawn Stick pacing, and interaction with datapacks or other global loot modifiers before final tuning. Option 2 means any enchantment grants full vanilla Diamond durability, while removing all enchantments restores fragility; tagged tools/Spear use 64 unenchanted durability and player armor uses 6x. Existing unenchanted Diamond gear changes automatically after update. Naturally test crafting, table/anvil/loot/command enchantments, Grindstone removal, durability bars/tooltips, break timing, repair/Mending interactions, deaths/containers, multiple equipment types, multiplayer, dedicated servers, and existing worlds. A stripped over-cap item deliberately retains one final use. Naturally verify animal-armor combat behavior, enchanting-table/anvil/SGA presentation, death drops, and multiplayer despite focused automated coverage. Also measure Steel's ordinary-fuel economy and naturally verify its recipes/stats/repairs/enchanting/trims and reused Iron visuals. Aenderite still provides only an ore/raw/ingot foundation. | | Environment | Death drops should despawn much later than vanilla, not never. | No implementation confirmed. | | Beds | Beds should not skip night; valid daytime bed rest is allowed when night skipping is disabled. | Healing behavior not confirmed implemented. | | Nether | Nether portal spread is planned as energy drain. | Needs bounded implementation design. | diff --git a/docs/internal/retold_mod_system.md b/docs/internal/retold_mod_system.md index 6db429d..5d3f1a2 100644 --- a/docs/internal/retold_mod_system.md +++ b/docs/internal/retold_mod_system.md @@ -167,7 +167,14 @@ use. every Horse and Nautilus Armor variant during default-component initialization. The `retold:animal_armor` item tag is included in the vanilla Chestplate, durability, and equippable enchantment families, giving those twelve items the same supported enchantment set as a player -Chestplate without including them in Retold's fragile Diamond player-armor tag. +Chestplate without including them in Retold's fragile Diamond player-armor tag. Horse and Nautilus +damage follows the ordinary `LivingEntity` enchantment pipeline. Wolf Armor instead absorbs most +hits directly into item durability before that pipeline runs, so the same owner listens for +incoming Wolf damage and applies vanilla `EnchantmentHelper` protection exactly once before the +absorption branch. Damage that bypasses Wolf Armor or enchantments is excluded from this bridge. +Fire Protection continues to reduce fire damage and burning duration rather than granting visual +fire immunity. Vanilla Horse and Nautilus armor remains indestructible, so durability-only +enchantments have no durability value to alter on those items. ## World Stage System diff --git a/docs/internal/tool_armor_ore_progression.md b/docs/internal/tool_armor_ore_progression.md index 73367ec..7bcbc93 100644 --- a/docs/internal/tool_armor_ore_progression.md +++ b/docs/internal/tool_armor_ore_progression.md @@ -494,7 +494,13 @@ Diamond armor follows the same low-unenchanted-durability rule as Diamond tools. Wolf Armor and all Horse and Nautilus Armor materials support the same enchantment compatibility set as a player Chestplate. Each animal armor uses its matching material's enchantability value; Wolf Armor uses the Armadillo Scute material value. Animal armor remains excluded from Diamond's -fragile-until-enchanted durability rule. +fragile-until-enchanted durability rule. Protection-family enchantments affect equipped animal +armor: the normal living-entity pipeline handles Horse and Nautilus health damage, while Retold +applies the same vanilla enchantment calculation before Wolf Armor converts a protected hit into +durability loss. Fire Protection reduces matching damage and burning duration; like a player +Chestplate, it does not make the animal visually fireproof. Horse and Nautilus armor remain +vanilla-indestructible, so durability-only enchantments have no durability pool to modify on those +items. Netherite upgrades Diamond gear. diff --git a/src/main/java/cz/xefensor/retold/enchanting/RetoldAnimalArmorEnchanting.java b/src/main/java/cz/xefensor/retold/enchanting/RetoldAnimalArmorEnchanting.java index 402f795..ec278fd 100644 --- a/src/main/java/cz/xefensor/retold/enchanting/RetoldAnimalArmorEnchanting.java +++ b/src/main/java/cz/xefensor/retold/enchanting/RetoldAnimalArmorEnchanting.java @@ -1,16 +1,24 @@ package cz.xefensor.retold.enchanting; import net.minecraft.core.component.DataComponents; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.tags.DamageTypeTags; +import net.minecraft.world.damagesource.CombatRules; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.animal.wolf.Wolf; import net.minecraft.world.item.Item; import net.minecraft.world.item.Items; import net.minecraft.world.item.enchantment.Enchantable; +import net.minecraft.world.item.enchantment.EnchantmentHelper; import net.minecraft.world.item.equipment.ArmorMaterial; import net.minecraft.world.item.equipment.ArmorMaterials; +import net.neoforged.bus.api.SubscribeEvent; import net.neoforged.neoforge.event.ModifyDefaultComponentsEvent; +import net.neoforged.neoforge.event.entity.living.LivingIncomingDamageEvent; import java.util.List; -/** Gives vanilla animal armor the enchantability of its matching armor material. */ +/** Owns vanilla animal-armor enchantability and Wolf Armor protection bridging. */ public final class RetoldAnimalArmorEnchanting { private static final List ANIMAL_ARMOR = List.of( armor(Items.WOLF_ARMOR, ArmorMaterials.ARMADILLO_SCUTE), @@ -44,6 +52,31 @@ public static void modifyDefaultComponents( } } + @SubscribeEvent + public static void applyEnchantmentsToAbsorbedWolfArmorDamage( + LivingIncomingDamageEvent event + ) { + if (!(event.getEntity() instanceof Wolf wolf) + || !(wolf.level() instanceof ServerLevel level) + || !wolf.getItemBySlot(EquipmentSlot.BODY).is(Items.WOLF_ARMOR) + || event.getSource().is(DamageTypeTags.BYPASSES_WOLF_ARMOR) + || event.getSource().is(DamageTypeTags.BYPASSES_ENCHANTMENTS)) { + return; + } + + float protection = EnchantmentHelper.getDamageProtection( + level, + wolf, + event.getSource() + ); + if (protection > 0.0F) { + event.setAmount(CombatRules.getDamageAfterMagicAbsorb( + event.getAmount(), + protection + )); + } + } + private static AnimalArmorDefinition armor( Item item, ArmorMaterial material diff --git a/src/main/java/cz/xefensor/retold/enchanting/RetoldEnchantingGameTests.java b/src/main/java/cz/xefensor/retold/enchanting/RetoldEnchantingGameTests.java index a64c693..07a1dd4 100644 --- a/src/main/java/cz/xefensor/retold/enchanting/RetoldEnchantingGameTests.java +++ b/src/main/java/cz/xefensor/retold/enchanting/RetoldEnchantingGameTests.java @@ -22,13 +22,21 @@ import net.minecraft.network.chat.Component; import net.minecraft.network.chat.FontDescription; import net.minecraft.resources.Identifier; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.entity.EntityTypes; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.ai.attributes.Attributes; +import net.minecraft.world.entity.animal.wolf.Wolf; import net.minecraft.world.inventory.AnvilMenu; import net.minecraft.world.inventory.EnchantmentMenu; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.item.enchantment.Enchantment; +import net.minecraft.world.item.enchantment.EnchantmentEffectComponents; import net.minecraft.world.item.enchantment.EnchantmentHelper; import net.minecraft.world.item.enchantment.Enchantments; import net.minecraft.world.item.enchantment.Enchantable; @@ -125,6 +133,13 @@ public static void register( RetoldEnchantingGameTests::animalArmorSupportsChestplateEnchantments ) ); + event.registerTest( + id("animal_armor_enchantments_affect_equipped_animals"), + new InlineGameTest( + testData, + RetoldEnchantingGameTests::animalArmorEnchantmentsAffectEquippedAnimals + ) + ); } private static void anvilTeachesOnlyTransferredEnchantments(GameTestHelper helper) { @@ -781,6 +796,290 @@ private static Set supportedEnchantments( .collect(Collectors.toUnmodifiableSet()); } + private static void animalArmorEnchantmentsAffectEquippedAnimals( + GameTestHelper helper + ) { + ServerLevel level = helper.getLevel(); + Wolf plainWolf = helper.spawn(EntityTypes.WOLF, 1, 2, 1); + Wolf protectedWolf = helper.spawn(EntityTypes.WOLF, 2, 2, 1); + Wolf plainFireWolf = helper.spawn(EntityTypes.WOLF, 3, 2, 1); + Wolf fireProtectedWolf = helper.spawn(EntityTypes.WOLF, 4, 2, 1); + Wolf thornsWolf = helper.spawn(EntityTypes.WOLF, 1, 2, 2); + var attacker = helper.spawn(EntityTypes.ZOMBIE, 4, 2, 2); + attacker.setNoAi(true); + + plainWolf.setItemSlot( + EquipmentSlot.BODY, + new ItemStack(Items.WOLF_ARMOR) + ); + protectedWolf.setItemSlot( + EquipmentSlot.BODY, + enchantedArmor(helper, Items.WOLF_ARMOR, Enchantments.PROTECTION, 4) + ); + plainFireWolf.setItemSlot( + EquipmentSlot.BODY, + new ItemStack(Items.WOLF_ARMOR) + ); + fireProtectedWolf.setItemSlot( + EquipmentSlot.BODY, + enchantedArmor( + helper, + Items.WOLF_ARMOR, + Enchantments.FIRE_PROTECTION, + 4 + ) + ); + thornsWolf.setItemSlot( + EquipmentSlot.BODY, + enchantedArmor(helper, Items.WOLF_ARMOR, Enchantments.THORNS, 255) + ); + + var plainHorse = helper.spawn(EntityTypes.HORSE, 1, 2, 3); + var protectedHorse = helper.spawn(EntityTypes.HORSE, 2, 2, 3); + plainHorse.setItemSlot( + EquipmentSlot.BODY, + new ItemStack(Items.IRON_HORSE_ARMOR) + ); + protectedHorse.setItemSlot( + EquipmentSlot.BODY, + enchantedArmor( + helper, + Items.IRON_HORSE_ARMOR, + Enchantments.FIRE_PROTECTION, + 4 + ) + ); + + var plainNautilus = helper.spawn(EntityTypes.NAUTILUS, 3, 2, 3); + var protectedNautilus = helper.spawn(EntityTypes.NAUTILUS, 4, 2, 3); + plainNautilus.setItemSlot( + EquipmentSlot.BODY, + new ItemStack(Items.IRON_NAUTILUS_ARMOR) + ); + protectedNautilus.setItemSlot( + EquipmentSlot.BODY, + enchantedArmor( + helper, + Items.IRON_NAUTILUS_ARMOR, + Enchantments.FIRE_PROTECTION, + 4 + ) + ); + + helper.runAfterDelay(2, () -> { + DamageSource genericDamage = level.damageSources().generic(); + DamageSource fireDamage = level.damageSources().lava(); + + plainWolf.hurtServer(level, genericDamage, 10.0F); + protectedWolf.hurtServer(level, genericDamage, 10.0F); + helper.assertTrue( + protectedWolf.getBodyArmorItem().getDamageValue() + < plainWolf.getBodyArmorItem().getDamageValue(), + "Protection must reduce damage absorbed by Wolf Armor" + ); + + plainFireWolf.hurtServer(level, fireDamage, 8.0F); + fireProtectedWolf.hurtServer(level, fireDamage, 8.0F); + helper.assertTrue( + fireProtectedWolf.getBodyArmorItem().getDamageValue() + < plainFireWolf.getBodyArmorItem().getDamageValue(), + "Fire Protection must reduce fire damage absorbed by Wolf Armor" + ); + fireProtectedWolf.igniteForTicks(100); + helper.assertTrue( + fireProtectedWolf.getRemainingFireTicks() < 100, + "Fire Protection must shorten an equipped animal's burning time" + ); + helper.assertTrue( + fireProtectedWolf.getAttributeValue(Attributes.BURNING_TIME) + < 1.0, + "Fire Protection must apply its burning-time attribute to BODY armor" + ); + + assertProtectionReducesAnimalDamage( + helper, + plainHorse, + protectedHorse, + fireDamage, + "Horse Armor" + ); + assertProtectionReducesAnimalDamage( + helper, + plainNautilus, + protectedNautilus, + fireDamage, + "Nautilus Armor" + ); + + float attackerHealth = attacker.getHealth(); + attacker.doHurtTarget(level, thornsWolf); + helper.assertTrue( + attacker.getHealth() < attackerHealth, + "Thorns on animal armor must retaliate against an attacker" + ); + + assertProtectionFamilyEffects(helper, protectedWolf); + assertDurabilityAndCurseEffects(helper); + helper.succeed(); + }); + } + + private static void assertProtectionReducesAnimalDamage( + GameTestHelper helper, + net.minecraft.world.entity.LivingEntity plainAnimal, + net.minecraft.world.entity.LivingEntity protectedAnimal, + DamageSource source, + String armorName + ) { + float plainHealth = plainAnimal.getHealth(); + float protectedHealth = protectedAnimal.getHealth(); + plainAnimal.hurtServer(helper.getLevel(), source, 8.0F); + protectedAnimal.hurtServer(helper.getLevel(), source, 8.0F); + helper.assertTrue( + protectedHealth - protectedAnimal.getHealth() + < plainHealth - plainAnimal.getHealth(), + "Fire Protection must reduce damage while wearing " + armorName + ); + } + + private static void assertProtectionFamilyEffects( + GameTestHelper helper, + Wolf wolf + ) { + assertProtectionEffect( + helper, + wolf, + Enchantments.PROTECTION, + helper.getLevel().damageSources().generic(), + "Protection" + ); + assertProtectionEffect( + helper, + wolf, + Enchantments.FIRE_PROTECTION, + helper.getLevel().damageSources().lava(), + "Fire Protection" + ); + assertProtectionEffect( + helper, + wolf, + Enchantments.BLAST_PROTECTION, + helper.getLevel().damageSources().explosion(null), + "Blast Protection" + ); + assertProtectionEffect( + helper, + wolf, + Enchantments.PROJECTILE_PROTECTION, + helper.getLevel().damageSources().source( + net.minecraft.world.damagesource.DamageTypes.ARROW + ), + "Projectile Protection" + ); + } + + private static void assertProtectionEffect( + GameTestHelper helper, + Wolf wolf, + ResourceKey enchantment, + DamageSource source, + String enchantmentName + ) { + wolf.setItemSlot( + EquipmentSlot.BODY, + enchantedArmor(helper, Items.WOLF_ARMOR, enchantment, 4) + ); + helper.assertTrue( + EnchantmentHelper.getDamageProtection( + helper.getLevel(), + wolf, + source + ) > 0.0F, + enchantmentName + " must contribute BODY-slot damage protection" + ); + } + + private static void assertDurabilityAndCurseEffects( + GameTestHelper helper + ) { + ItemStack unbreakingArmor = enchantedArmor( + helper, + Items.WOLF_ARMOR, + Enchantments.UNBREAKING, + 3 + ); + helper.assertTrue( + EnchantmentHelper.processDurabilityChange( + helper.getLevel(), + unbreakingArmor, + 1_000 + ) < 1_000, + "Unbreaking must reduce Wolf Armor durability loss" + ); + + ItemStack mendingArmor = enchantedArmor( + helper, + Items.WOLF_ARMOR, + Enchantments.MENDING, + 1 + ); + helper.assertValueEqual( + EnchantmentHelper.modifyDurabilityToRepairFromXp( + helper.getLevel(), + mendingArmor, + 1 + ), + 2, + "Mending must retain its normal repair conversion on Wolf Armor" + ); + + ItemStack bindingArmor = enchantedArmor( + helper, + Items.WOLF_ARMOR, + Enchantments.BINDING_CURSE, + 1 + ); + helper.assertTrue( + EnchantmentHelper.has( + bindingArmor, + EnchantmentEffectComponents.PREVENT_ARMOR_CHANGE + ), + "Curse of Binding must prevent ordinary animal-armor removal" + ); + + ItemStack vanishingArmor = enchantedArmor( + helper, + Items.WOLF_ARMOR, + Enchantments.VANISHING_CURSE, + 1 + ); + helper.assertTrue( + EnchantmentHelper.has( + vanishingArmor, + EnchantmentEffectComponents.PREVENT_EQUIPMENT_DROP + ), + "Curse of Vanishing must suppress animal-armor death drops" + ); + } + + private static ItemStack enchantedArmor( + GameTestHelper helper, + Item item, + ResourceKey enchantmentKey, + int level + ) { + Holder enchantment = helper.getLevel() + .registryAccess() + .lookupOrThrow(Registries.ENCHANTMENT) + .getOrThrow(enchantmentKey); + ItemStack armor = new ItemStack(item); + EnchantmentHelper.updateEnchantments( + armor, + enchantments -> enchantments.set(enchantment, level) + ); + return armor; + } + private static boolean containsEnchantment( List definitions, Identifier enchantment diff --git a/src/main/java/cz/xefensor/retold/module/RetoldFoundationModule.java b/src/main/java/cz/xefensor/retold/module/RetoldFoundationModule.java index ebaca9d..4b4d8a6 100644 --- a/src/main/java/cz/xefensor/retold/module/RetoldFoundationModule.java +++ b/src/main/java/cz/xefensor/retold/module/RetoldFoundationModule.java @@ -51,6 +51,7 @@ public static void registerModBus(IEventBus modEventBus) { public static void registerGameBus(IEventBus gameEventBus) { gameEventBus.register(RetoldAnvilLearningEvents.class); + gameEventBus.register(RetoldAnimalArmorEnchanting.class); gameEventBus.register(RetoldEnchantmentCatalogSyncEvents.class); gameEventBus.register(RetoldCommandEvents.class); gameEventBus.register(RetoldPlayerSyncEvents.class); From 37b14790b97d3c966e46907465167286c92303ff Mon Sep 17 00:00:00 2001 From: xefensor Date: Wed, 12 Aug 2026 00:19:13 +0200 Subject: [PATCH 04/11] Extend enchanted durability to all diamond gear --- CHANGELOG.md | 4 +- docs/internal/design_implementation_status.md | 4 +- docs/internal/retold_design_risks.md | 2 +- docs/internal/retold_mod_system.md | 13 +- docs/internal/tool_armor_ore_progression.md | 19 +-- .../RetoldAnimalArmorEnchanting.java | 41 ++++++- .../progression/RetoldDiamondDurability.java | 31 ++++- .../RetoldToolProgressionGameTests.java | 115 ++++++++++++++++++ .../fragile_unenchanted_diamond_armor.json | 4 +- 9 files changed, 203 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 18e18b4..d3f3b37 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,7 @@ Each release should be readable in two passes: - The survival opening now begins with Sticks and Flint instead of punching logs. Leaves have an additional 20% chance to drop 1–2 Sticks, increasing by five percentage points per Fortune level; shears and Silk Touch retain their normal leaf-block harvest without the extra drop. Logs require a suitable tool, the 2x2 Flint Multi-tool harvests the first wood, exposed Copper, and soft early stone, and vanilla Wooden and Stone tool recipes no longer bypass the material ladder. Copper generation now makes six vein attempts per chunk instead of sixteen while preserving normal vein sizes, reducing cave-wall clutter without making each discovery unrewarding. Copper Pickaxes can harvest normal Stone for Cobblestone, but do so at 25% speed until Iron makes ordinary mining practical. - Campfires are now crafted from three Sticks and three Logs without Coal or Flint and begin unlit immediately when placed, without briefly flashing their lit appearance. Using a bare Flint lights one and consumes that Flint in Survival, while Flint and Steel retains its normal durability-based ignition. Clay Balls fire into Bricks on a Campfire; eight Bricks in a ring then craft the Brick Furnace, Retold's renamed Smoker. It keeps food cooking, makes Charcoal from burnable logs, and processes Raw Copper and both Copper ores so players can reach Copper before obtaining Cobblestone for a normal Furnace. - Blast Furnaces now process Iron Ingots directly into Steel Ingots using any ordinary fuel. Steel provides a full Pickaxe, Axe, Shovel, Hoe, Sword, and armor tier between Iron and Diamond. Copper and Iron remain painfully slow on Deepslate-family blocks, while Steel restores full deep-mining speed, harvests deep Diamond Ore, and still leaves Obsidian to Diamond. -- Unenchanted Diamond tools and Spears now have only 64 durability, while unenchanted Diamond player armor has leather-like 6x durability. Any enchantment immediately restores full vanilla Diamond durability; removing every enchantment makes the item fragile again. A heavily damaged item stripped beyond that fragile limit retains one final use instead of becoming invalid immediately. +- Unenchanted Diamond tools and Spears now have only 64 durability, while unenchanted Diamond armor has leather-like 6x durability. Diamond Horse and Nautilus Armor now use 96 durability before enchanting and 528 afterward, and lose durability from real hits like other armor. Any enchantment immediately restores full Diamond durability; removing every enchantment makes the item fragile again. A heavily damaged item stripped beyond that fragile limit retains one final use instead of becoming invalid immediately. - Wolf Armor and every Horse and Nautilus Armor material can now be enchanted with the same enchantment pool as a Chestplate. Each uses the enchanting value of its own armor material. Protection enchantments now affect damage absorbed by Wolf Armor as well as ordinary animal health damage; Fire Protection also retains its normal shorter-burning effect. - The End no longer produces its periodic celestial flashes, temporary brightness pulses, or delayed flash sounds. Retold's generated End sky remains unchanged. - Trial Chambers, Ancient Cities, and the Deep Dark no longer generate in newly explored terrain. Their blocks, items, mobs, biomes, and already-generated content remain available. @@ -26,7 +26,7 @@ Each release should be readable in two passes: ### Technical - Added the 48-durability Flint Multi-tool and provisional Steel material with data-driven mining, repair, common-ingot, enchantment-family, and armor tags. A global loot modifier supplies additional Sticks from every block in `minecraft:leaves`, and placed-feature overrides reduce both ordinary and Dripstone Copper attempts from sixteen to six per chunk. Exact Wooden/Stone recipes are removed during recipe loading; Armorer, Toolsmith, and Weaponsmith lessons follow the material ladder. Five focused GameTests cover leaf Stick supply, reduced Copper placement across seeded chunk-border samples, the unfueled Campfire recipe and ignition behavior, harvest tiers through Steel, Copper/Deepslate pacing, starter and equipment crafting, Brick Furnace processing, normal Iron-to-Steel blasting, and Furnace availability. -- Added tag-driven dynamic Diamond durability through a narrow `ItemStack.getMaxDamage` hook and a named progression policy. Focused coverage verifies fragile tool/armor values, enchantment restoration, removal regression, vanilla-tag preservation, and the over-damaged stripped-item safeguard. +- Added tag-driven dynamic Diamond durability through a narrow `ItemStack.getMaxDamage` hook and a named progression policy. Diamond Horse and Nautilus Armor receive a 528-durability component and server-side BODY-slot wear from non-bypassing hits. Focused coverage enumerates all twelve enchantable Diamond items and verifies fragile values, enchantment restoration, removal regression, real animal-armor wear, vanilla-tag preservation, and the over-damaged stripped-item safeguard. - Added data-driven Chestplate enchantment compatibility and material-matched enchantability components for all twelve vanilla animal armors. A Wolf-specific incoming-damage bridge applies vanilla enchantment protection before Wolf Armor's special durability-absorption path bypasses ordinary living-entity mitigation. Focused coverage verifies every supported-enchantment set plus equipped Protection-family mitigation, Fire Protection burn duration, Thorns, Unbreaking, Mending, Binding, and Vanishing behavior across Wolf, Horse, and Nautilus armor paths. - Added a client-only vanilla-End hook that clears `EndFlashState` after level construction, suppressing all flash rendering, lightmap, and sound paths while preserving the End skybox and leaving other End-style dimensions untouched. - Replaced the vanilla Trial Chamber and Ancient City biome tags with empty tags so the structures remain registered but have no eligible generation biomes. A narrow Overworld biome-builder hook omits the Deep Dark mapping from the default climate preset without unregistering the biome. Added focused GameTest coverage for each boundary. diff --git a/docs/internal/design_implementation_status.md b/docs/internal/design_implementation_status.md index 3636760..14f926b 100644 --- a/docs/internal/design_implementation_status.md +++ b/docs/internal/design_implementation_status.md @@ -168,8 +168,8 @@ Largest missing or partial design areas: | Reduced Copper generation | Implemented / needs fresh-world verification | Both `minecraft:ore_copper` and `minecraft:ore_copper_large` now make six placement attempts per chunk instead of sixteen, a 62.5% frequency reduction. Vanilla size-10 ordinary and size-20 Dripstone veins plus their height distribution are preserved. A focused registry-backed GameTest verifies both loaded overrides across three seeded origins spanning a chunk border; several fresh seeds, cave-wall exposure, and existing-versus-new chunk behavior still need natural verification. | | Flint/copper/iron/steel/diamond tool progression | Partial / needs verification | Progression is implemented through Diamond: Wooden/Stone recipes are removed, Copper and Steel geology pacing is active, and unenchanted tagged Diamond tools/Spear use 64 durability while any enchantment restores their vanilla maximum. Removing every enchantment makes them fragile again. Focused tests cover the boundaries and transitions. Netherite/Aenderite equipment and final balance remain incomplete. | | Campfire, Brick Furnace, Furnace, Blast Furnace, and parallel enchanting progression | Partial / needs verification | Campfires use a fuel-free three-Stick/three-Log recipe. Their initial placement state is unlit on both logical sides, avoiding the former client-visible lit-state flash. Bare Flint ignites one and is consumed in Survival; Flint and Steel retains normal durability use. Campfire cooking fires Clay Balls into Bricks, and eight Bricks craft the Smoker-backed Brick Furnace. The Brick and normal Furnace roles are implemented. Per the 2026-08-11 choice, a standard 100-tick blasting recipe converts one Iron Ingot to one Steel Ingot while accepting ordinary Blast Furnace fuels; Charcoal is valid but not mandatory or fixed 1:1. Blast Furnace construction remains vanilla. Enchanting follows the separate deterministic SGA system. | -| Leather/copper/iron/steel/diamond armor progression | Partial / needs verification | Steel has its provisionally balanced four-piece set. Unenchanted Diamond player armor now uses 6x durability (66/96/90/78), while any enchantment restores vanilla 33x durability and removing all enchantments restores fragility. All twelve Wolf, Horse, and Nautilus Armor items support the exact Chestplate enchantment set and use their material's enchantability value; animal armor remains excluded from Diamond fragility. A focused equipped-animal test covers Protection-family mitigation, Fire Protection burn duration, Thorns, Unbreaking, Mending, Binding, and Vanishing paths. Retold bridges protection into Wolf Armor's special absorbed-durability path; Horse and Nautilus armor use vanilla health mitigation and remain indestructible. Later Retold armor tiers remain incomplete. | -| Diamond tools weak unless enchanted | Implemented / needs in-game verification | A narrow `ItemStack` hook delegates to `RetoldDiamondDurability`; tagged unenchanted tools use 64 durability and enchanted tools use their vanilla maximum. Stripping a heavily damaged item preserves its damage and leaves one final use rather than an invalid stack. Focused coverage verifies tool and armor enchant/remove transitions and the damaged-item edge case. | +| Leather/copper/iron/steel/diamond armor progression | Partial / needs verification | Steel has its provisionally balanced four-piece set. Unenchanted Diamond player armor uses 6x durability (66/96/90/78), while any enchantment restores 33x durability and removing all enchantments restores fragility. Diamond Horse and Nautilus Armor now follow the BODY/Chestplate 96/528 durability transition and take wear from real hits; non-Diamond animal armor remains indestructible. All twelve Wolf, Horse, and Nautilus Armor items support the exact Chestplate enchantment set and use their material's enchantability value. Focused equipped-animal tests cover damage wear, Protection-family mitigation, Fire Protection burn duration, Thorns, Unbreaking, Mending, Binding, and Vanishing paths. Retold bridges protection into Wolf Armor's special absorbed-durability path, while Horse and Nautilus armor use vanilla health mitigation. Later Retold armor tiers remain incomplete. | +| Diamond tools weak unless enchanted | Implemented / needs in-game verification | A narrow `ItemStack` hook delegates to `RetoldDiamondDurability`; all twelve enchantable Diamond items use fragile unenchanted durability and their full maximum while enchanted. Stripping a heavily damaged item preserves its damage and leaves one final use rather than an invalid stack. Focused coverage enumerates the complete set, verifies enchant/remove transitions and the damaged-item edge case, and confirms Diamond Horse/Nautilus Armor wear on real hits. | | Aenderite ore and refined material | Partial / needs verification | Aenderite generates at diamond-like abundance inside Aender Stone, using mostly 3–4 and 4–8 block veins with rare 8–12 block veins, biased toward island undersides. A Netherite Pickaxe is required; Silk Touch preserves the ore, Fortune applies to Raw Aenderite, and raw material smelts/blasts into an ingot. Tools, armor, blocks, and other ingot uses are intentionally not designed yet. | | Enchanting rework | Partial / needs interaction verification | All 43 currently registered enchantments have unique data-driven `domain + effect + modifier` definitions using the fixed 26-concept SGA vocabulary. Duplicate enchantment/word mappings and unknown concepts are rejected atomically, and the validated catalog is synchronized to clients on join and datapack reload. Known enchantment ids persist per player and each receiving client gets its server-authoritative knowledge snapshot. Completed anvil use teaches only book enchantments that actually increased the result compared with the left input. Unknown mapped tooltip entries show only SGA plus level; known entries retain their readable name and add the SGA word. The developer confirmed tooltip behavior and accepted the current table layout in-game on 2026-08-09. The deterministic table transaction, item-aware known-spell filtering, registered maximum display/limits, green success clearing/highlight, and generic low-note/red-highlight rejection cue are implemented with focused coverage. The newest filtering/feedback interaction and dedicated multiplayer synchronization still need verification. | | Iron rods/sticks crafting changes | Not implemented | diff --git a/docs/internal/retold_design_risks.md b/docs/internal/retold_design_risks.md index 96a1df5..24d7b6c 100644 --- a/docs/internal/retold_design_risks.md +++ b/docs/internal/retold_design_risks.md @@ -33,7 +33,7 @@ | Villages | Container, Farmer-crop, and profession-tended livestock offenses use witnessed vanilla gossip. Sight and village-context checks can be sensitive to walls, crowded settlements, vertical farms, merged double chests, animal transport, automation, and multiplayer timing. | Generated village loot plus Villager-produced quantities are protected; player deposits and ambiguous already-opened existing-world contents are not. Farmer planting/replanting marks persistent crop positions. Shepherds, Leatherworkers, and Butchers claim only animals they successfully feed with two real storage items; player interaction/leashing marks previously unowned livestock as player-associated. Offspring of two owned parents inherit persisted village ownership, while an automatic offspring of a player-associated unowned parent inherits player protection. Witnessed direct Survival kills add `-50`; monsters, environment, Creative, and Spectator do not. Four focused animal tests plus the crop/container groups cover persistence, ownership separation, conservation, offense strengths, witnesses, and exclusions; the latest 50-Villager TPS peak is 6.864 ms/tick. Naturally verify physical storage-to-pen routes, wandering/boat-transport edge cases, full harvest/replant cycles, trade prices, golem reaction, double chests, hoppers, simultaneous players, dedicated servers, and existing worlds before calling the loop fully verified. | | Stage 3 | Raid creation is now gated to Stage 3, but the broader illager behavior may need clearer player-facing feedback later. | Avoid major raid redesign without developer approval. The Stage 2 live creation rejection and Witch/Illager same-raid cooperation are regression-tested; natural Bad Omen preservation, Stage 3 Raid Omen conversion, wave participation, healing, and raid-exit behavior still need in-game verification. Existing raids deliberately continue if an administrative command moves the world back below Stage 3. | | Piglins | Stage 3 piglin/pigman hiring or follower behavior is planned but not implemented. | Needs feature design. | -| Items | The implemented Flint-through-Diamond spine changes first-spawn assumptions, leaf loot, Copper distribution, Campfire ignition, recipes, station use, mining speed, nine Steel equipment items, animal-armor enchanting, and the effective maximum durability of existing Diamond equipment. Its provisional balance, fuel economy, compatibility, and reused visuals need validation. Later equipment, mending removal, and combat reworks remain planned. | Focused GameTests cover the material ladder through Steel, six-attempt ordinary/large Copper placement across seeded chunk-border origins while retaining vanilla vein sizes, the 20% supplemental 1–2 Stick leaf roll and its Fortune/shears/Silk Touch boundaries, the fuel-free Campfire recipe, the real unlit initial placement-state hook, consumable bare-Flint ignition, durable Flint and Steel ignition, Clay-to-Brick campfire cooking, and the eight-Brick furnace boundary, plus dynamic Diamond tool/armor durability, enchant/remove transitions, the heavily damaged stripped-item edge case, all twelve animal armors' exact Chestplate enchantment compatibility, and equipped-animal Protection-family, fire-duration, Thorns, durability, Mending, and curse paths. Wolf Armor's special absorption path now applies vanilla enchantment protection before converting damage into durability loss; Fire Protection remains damage/duration reduction rather than immunity, and indestructible Horse/Nautilus armor gives durability-only enchantments no durability pool to change. The Copper override affects only newly generated chunks; naturally inspect multiple fresh seeds, ordinary and Dripstone caves, cave-wall exposure, chunk borders, early acquisition time, and datapack/worldgen-mod compatibility before further tuning. Visually verify that Campfire placement no longer flashes lit on the client, plus cooking four Clay items, water/extinguishing, Creative consumption exemption, automation, recipe-book presentation, multiplayer, and compatibility with Campfire/recipe mods. Also verify leaf breaking and decay, explosions, non-Oak and modded tagged leaves, first-spawn Stick pacing, and interaction with datapacks or other global loot modifiers before final tuning. Option 2 means any enchantment grants full vanilla Diamond durability, while removing all enchantments restores fragility; tagged tools/Spear use 64 unenchanted durability and player armor uses 6x. Existing unenchanted Diamond gear changes automatically after update. Naturally test crafting, table/anvil/loot/command enchantments, Grindstone removal, durability bars/tooltips, break timing, repair/Mending interactions, deaths/containers, multiple equipment types, multiplayer, dedicated servers, and existing worlds. A stripped over-cap item deliberately retains one final use. Naturally verify animal-armor combat behavior, enchanting-table/anvil/SGA presentation, death drops, and multiplayer despite focused automated coverage. Also measure Steel's ordinary-fuel economy and naturally verify its recipes/stats/repairs/enchanting/trims and reused Iron visuals. Aenderite still provides only an ore/raw/ingot foundation. | +| Items | The implemented Flint-through-Diamond spine changes first-spawn assumptions, leaf loot, Copper distribution, Campfire ignition, recipes, station use, mining speed, nine Steel equipment items, animal-armor enchanting, and the effective maximum durability of existing Diamond equipment. Its provisional balance, fuel economy, compatibility, and reused visuals need validation. Later equipment, mending removal, and combat reworks remain planned. | Focused GameTests cover the material ladder through Steel, six-attempt ordinary/large Copper placement across seeded chunk-border origins while retaining vanilla vein sizes, the 20% supplemental 1–2 Stick leaf roll and its Fortune/shears/Silk Touch boundaries, the fuel-free Campfire recipe, the real unlit initial placement-state hook, consumable bare-Flint ignition, durable Flint and Steel ignition, Clay-to-Brick campfire cooking, and the eight-Brick furnace boundary, plus all twelve enchantable Diamond items' dynamic durability, enchant/remove transitions, the heavily damaged stripped-item edge case, real Diamond Horse/Nautilus Armor wear, all twelve animal armors' exact Chestplate enchantment compatibility, and equipped-animal Protection-family, fire-duration, Thorns, durability, Mending, and curse paths. Wolf Armor's special absorption path applies vanilla enchantment protection before converting damage into durability loss; Fire Protection remains damage/duration reduction rather than immunity. Diamond Horse and Nautilus Armor now use 96/528 durability, while non-Diamond variants remain indestructible. The Copper override affects only newly generated chunks; naturally inspect multiple fresh seeds, ordinary and Dripstone caves, cave-wall exposure, chunk borders, early acquisition time, and datapack/worldgen-mod compatibility before further tuning. Visually verify that Campfire placement no longer flashes lit on the client, plus cooking four Clay items, water/extinguishing, Creative consumption exemption, automation, recipe-book presentation, multiplayer, and compatibility with Campfire/recipe mods. Also verify leaf breaking and decay, explosions, non-Oak and modded tagged leaves, first-spawn Stick pacing, and interaction with datapacks or other global loot modifiers before final tuning. Option 2 means any enchantment grants full Diamond durability, while removing all enchantments restores fragility; tagged tools/Spear use 64 unenchanted durability and player/body armor uses 6x. Existing unenchanted Diamond gear changes automatically after update. Naturally test crafting, table/anvil/loot/command enchantments, Grindstone removal, durability bars/tooltips, break timing, repair/Mending interactions, deaths/containers, multiple equipment types, multiplayer, dedicated servers, and existing worlds. A stripped over-cap item deliberately retains one final use. Naturally verify animal-armor combat behavior, enchanting-table/anvil/SGA presentation, death drops, and multiplayer despite focused automated coverage. Also measure Steel's ordinary-fuel economy and naturally verify its recipes/stats/repairs/enchanting/trims and reused Iron visuals. Aenderite still provides only an ore/raw/ingot foundation. | | Environment | Death drops should despawn much later than vanilla, not never. | No implementation confirmed. | | Beds | Beds should not skip night; valid daytime bed rest is allowed when night skipping is disabled. | Healing behavior not confirmed implemented. | | Nether | Nether portal spread is planned as energy drain. | Needs bounded implementation design. | diff --git a/docs/internal/retold_mod_system.md b/docs/internal/retold_mod_system.md index 5d3f1a2..90ffe14 100644 --- a/docs/internal/retold_mod_system.md +++ b/docs/internal/retold_mod_system.md @@ -157,24 +157,25 @@ until final art is approved. `RetoldDiamondDurability` owns the selected dynamic Diamond rule. `ItemStackDiamondDurabilityMixin` is only the return-value hook for `ItemStack.getMaxDamage`; separate item tags identify affected -Diamond tools/Spear and player armor. Unenchanted tools use 64 durability and armor scales from -vanilla's 33x to 6x. Any enchantment restores the underlying vanilla maximum, while removing all +Diamond tools/Spear and armor. Unenchanted tools use 64 durability and armor scales from vanilla's +33x to 6x. Diamond Horse and Nautilus Armor receive the BODY/Chestplate base of 528, producing 96 +unenchanted durability. Any enchantment restores the underlying full maximum, while removing all enchantments restores fragility. Raw damage is read directly from the component so the hook cannot re-enter itself; an over-cap stripped item receives an effective `damage + 1` maximum and one final -use. +use. A `LivingDamageEvent.Pre` handler gives those two BODY-slot items normal armor wear after a +non-armor-bypassing hit; `ItemStack.hurtAndBreak` retains Unbreaking and break behavior. `RetoldAnimalArmorEnchanting` adds material-matched enchantability components to Wolf Armor and every Horse and Nautilus Armor variant during default-component initialization. The `retold:animal_armor` item tag is included in the vanilla Chestplate, durability, and equippable enchantment families, giving those twelve items the same supported enchantment set as a player -Chestplate without including them in Retold's fragile Diamond player-armor tag. Horse and Nautilus +Chestplate. Diamond Horse and Nautilus Armor also join Retold's fragile Diamond armor tag. Horse and Nautilus damage follows the ordinary `LivingEntity` enchantment pipeline. Wolf Armor instead absorbs most hits directly into item durability before that pipeline runs, so the same owner listens for incoming Wolf damage and applies vanilla `EnchantmentHelper` protection exactly once before the absorption branch. Damage that bypasses Wolf Armor or enchantments is excluded from this bridge. Fire Protection continues to reduce fire damage and burning duration rather than granting visual -fire immunity. Vanilla Horse and Nautilus armor remains indestructible, so durability-only -enchantments have no durability value to alter on those items. +fire immunity. Non-Diamond Horse and Nautilus armor retains vanilla's indestructible behavior. ## World Stage System diff --git a/docs/internal/tool_armor_ore_progression.md b/docs/internal/tool_armor_ore_progression.md index 7bcbc93..241a346 100644 --- a/docs/internal/tool_armor_ore_progression.md +++ b/docs/internal/tool_armor_ore_progression.md @@ -350,6 +350,8 @@ The developer chose dynamic durability on 2026-08-11: - unenchanted Diamond Sword, Shovel, Pickaxe, Axe, Hoe, and Spear have 64 maximum durability - unenchanted Diamond player armor uses durability multiplier 6: Helmet 66, Chestplate 96, Leggings 90, and Boots 78 +- unenchanted Diamond Horse and Nautilus Armor use the BODY/Chestplate value of 96 durability; + enchanting either restores its full 528 durability - while any enchantment is present, the item immediately uses its full vanilla Diamond durability - removing every enchantment, including through a Grindstone, immediately restores the fragile maximum @@ -357,8 +359,9 @@ The developer chose dynamic durability on 2026-08-11: temporarily `damage + 1`, leaving one final use instead of creating an already-broken stack - re-enchanting the item restores the full maximum again without changing its preserved damage -This rule is data-driven through separate Retold Diamond tool and player-armor tags. Horse and -Nautilus armor are not included. +This rule is data-driven through separate Retold Diamond tool and armor tags. The armor tag covers +player armor plus Diamond Horse and Nautilus Armor, which Retold makes damageable because vanilla +animal armor does not otherwise have durability. The intended relationship is: @@ -493,14 +496,14 @@ Diamond armor follows the same low-unenchanted-durability rule as Diamond tools. Wolf Armor and all Horse and Nautilus Armor materials support the same enchantment compatibility set as a player Chestplate. Each animal armor uses its matching material's enchantability value; -Wolf Armor uses the Armadillo Scute material value. Animal armor remains excluded from Diamond's -fragile-until-enchanted durability rule. Protection-family enchantments affect equipped animal +Wolf Armor uses the Armadillo Scute material value. Diamond Horse and Nautilus Armor follow +Diamond's fragile-until-enchanted durability rule at 96/528 durability and receive BODY-slot wear +from non-armor-bypassing hits. Protection-family enchantments affect equipped animal armor: the normal living-entity pipeline handles Horse and Nautilus health damage, while Retold applies the same vanilla enchantment calculation before Wolf Armor converts a protected hit into durability loss. Fire Protection reduces matching damage and burning duration; like a player -Chestplate, it does not make the animal visually fireproof. Horse and Nautilus armor remain -vanilla-indestructible, so durability-only enchantments have no durability pool to modify on those -items. +Chestplate, it does not make the animal visually fireproof. Non-Diamond Horse and Nautilus armor +retains vanilla's indestructible behavior. Netherite upgrades Diamond gear. @@ -542,7 +545,7 @@ Copper rate again only from concrete natural-world results. - Copper and Steel receive full tool and armor sets. - Standard tool families follow the same tier ladder from Copper onward. - Diamond equipment has very low durability until enchanted. -- Diamond durability is dynamic: removing every enchantment makes tagged Diamond tools and player armor fragile again. +- Diamond durability is dynamic: removing every enchantment makes tagged Diamond tools, player armor, Horse Armor, and Nautilus Armor fragile again. - Netherite sits between Diamond and Aenderite and upgrades Diamond equipment. - Aenderite is the final exotic tier but must have an identity beyond bigger stats. - Keep vanilla Iron and Diamond generation; Copper is the confirmed exception at six vein attempts per chunk with vanilla vein sizes. diff --git a/src/main/java/cz/xefensor/retold/enchanting/RetoldAnimalArmorEnchanting.java b/src/main/java/cz/xefensor/retold/enchanting/RetoldAnimalArmorEnchanting.java index ec278fd..4686d89 100644 --- a/src/main/java/cz/xefensor/retold/enchanting/RetoldAnimalArmorEnchanting.java +++ b/src/main/java/cz/xefensor/retold/enchanting/RetoldAnimalArmorEnchanting.java @@ -1,10 +1,12 @@ package cz.xefensor.retold.enchanting; +import cz.xefensor.retold.progression.RetoldDiamondDurability; import net.minecraft.core.component.DataComponents; import net.minecraft.server.level.ServerLevel; import net.minecraft.tags.DamageTypeTags; import net.minecraft.world.damagesource.CombatRules; import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.animal.wolf.Wolf; import net.minecraft.world.item.Item; import net.minecraft.world.item.Items; @@ -14,12 +16,18 @@ import net.minecraft.world.item.equipment.ArmorMaterials; import net.neoforged.bus.api.SubscribeEvent; import net.neoforged.neoforge.event.ModifyDefaultComponentsEvent; +import net.neoforged.neoforge.event.entity.living.LivingDamageEvent; import net.neoforged.neoforge.event.entity.living.LivingIncomingDamageEvent; import java.util.List; +import java.util.Set; -/** Owns vanilla animal-armor enchantability and Wolf Armor protection bridging. */ +/** Owns animal-armor enchanting, protection bridging, and Diamond wear. */ public final class RetoldAnimalArmorEnchanting { + private static final Set DURABLE_DIAMOND_ANIMAL_ARMOR = Set.of( + Items.DIAMOND_HORSE_ARMOR, + Items.DIAMOND_NAUTILUS_ARMOR + ); private static final List ANIMAL_ARMOR = List.of( armor(Items.WOLF_ARMOR, ArmorMaterials.ARMADILLO_SCUTE), armor(Items.LEATHER_HORSE_ARMOR, ArmorMaterials.LEATHER), @@ -44,10 +52,20 @@ public static void modifyDefaultComponents( for (AnimalArmorDefinition definition : ANIMAL_ARMOR) { event.modify( definition.item(), - (components, context, item) -> components.set( - DataComponents.ENCHANTABLE, - new Enchantable(definition.enchantability()) - ) + (components, context, item) -> { + components.set( + DataComponents.ENCHANTABLE, + new Enchantable(definition.enchantability()) + ); + if (DURABLE_DIAMOND_ANIMAL_ARMOR.contains(item)) { + components.set( + DataComponents.MAX_DAMAGE, + RetoldDiamondDurability + .DIAMOND_BODY_ARMOR_DURABILITY + ); + components.set(DataComponents.DAMAGE, 0); + } + } ); } } @@ -77,6 +95,19 @@ public static void applyEnchantmentsToAbsorbedWolfArmorDamage( } } + @SubscribeEvent + public static void hurtDurableDiamondAnimalArmor( + LivingDamageEvent.Pre event + ) { + if (event.getEntity() instanceof Mob mob + && !event.getSource().is(DamageTypeTags.BYPASSES_ARMOR)) { + RetoldDiamondDurability.hurtAnimalBodyArmor( + mob, + event.getOriginalDamage() + ); + } + } + private static AnimalArmorDefinition armor( Item item, ArmorMaterial material diff --git a/src/main/java/cz/xefensor/retold/progression/RetoldDiamondDurability.java b/src/main/java/cz/xefensor/retold/progression/RetoldDiamondDurability.java index 902684b..ad18856 100644 --- a/src/main/java/cz/xefensor/retold/progression/RetoldDiamondDurability.java +++ b/src/main/java/cz/xefensor/retold/progression/RetoldDiamondDurability.java @@ -2,10 +2,13 @@ import cz.xefensor.retold.registry.RetoldTags; import net.minecraft.core.component.DataComponents; +import net.minecraft.world.entity.EquipmentSlot; +import net.minecraft.world.entity.Mob; import net.minecraft.world.item.ItemStack; public final class RetoldDiamondDurability { public static final int UNENCHANTED_TOOL_DURABILITY = 64; + public static final int DIAMOND_BODY_ARMOR_DURABILITY = 528; private static final int ARMOR_DURABILITY_NUMERATOR = 6; private static final int VANILLA_DIAMOND_ARMOR_DURABILITY = 33; @@ -26,11 +29,7 @@ public static int effectiveMaxDamage( } else if (stack.is( RetoldTags.FRAGILE_UNENCHANTED_DIAMOND_ARMOR )) { - fragileMaxDamage = Math.max( - 1, - baseMaxDamage * ARMOR_DURABILITY_NUMERATOR - / VANILLA_DIAMOND_ARMOR_DURABILITY - ); + fragileMaxDamage = fragileArmorDurability(baseMaxDamage); } else { return baseMaxDamage; } @@ -44,4 +43,26 @@ public static int effectiveMaxDamage( Math.max(fragileMaxDamage, minimumValidMaxDamage) ); } + + public static int fragileArmorDurability(int fullDurability) { + return Math.max( + 1, + fullDurability * ARMOR_DURABILITY_NUMERATOR + / VANILLA_DIAMOND_ARMOR_DURABILITY + ); + } + + public static void hurtAnimalBodyArmor(Mob mob, float incomingDamage) { + if (incomingDamage <= 0.0F) { + return; + } + + ItemStack bodyArmor = mob.getItemBySlot(EquipmentSlot.BODY); + if (!bodyArmor.is(RetoldTags.FRAGILE_UNENCHANTED_DIAMOND_ARMOR)) { + return; + } + + int durabilityDamage = Math.max(1, (int) (incomingDamage / 4.0F)); + bodyArmor.hurtAndBreak(durabilityDamage, mob, EquipmentSlot.BODY); + } } diff --git a/src/main/java/cz/xefensor/retold/progression/RetoldToolProgressionGameTests.java b/src/main/java/cz/xefensor/retold/progression/RetoldToolProgressionGameTests.java index 9f45fd8..e907ca5 100644 --- a/src/main/java/cz/xefensor/retold/progression/RetoldToolProgressionGameTests.java +++ b/src/main/java/cz/xefensor/retold/progression/RetoldToolProgressionGameTests.java @@ -1,10 +1,12 @@ package cz.xefensor.retold.progression; import cz.xefensor.retold.registry.RetoldBlocks; +import cz.xefensor.retold.registry.RetoldTags; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.Holder; import net.minecraft.core.component.DataComponents; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.Registries; import net.minecraft.gametest.framework.BuiltinTestFunctions; import net.minecraft.gametest.framework.FunctionGameTestInstance; @@ -18,6 +20,8 @@ import net.minecraft.util.RandomSource; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.EntityTypes; +import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; @@ -56,7 +60,9 @@ import java.util.List; import java.util.Optional; +import java.util.Set; import java.util.function.Consumer; +import java.util.stream.Collectors; public final class RetoldToolProgressionGameTests { private static final Identifier EMPTY_STRUCTURE = @@ -135,6 +141,115 @@ public static void register( "tool_progression_copper_generation_is_reduced", RetoldToolProgressionGameTests::copperGenerationIsReduced ); + registerTest( + event, + environment, + "tool_progression_all_diamond_items_require_enchanting_for_durability", + RetoldToolProgressionGameTests + ::allDiamondItemsRequireEnchantingForDurability + ); + } + + private static void allDiamondItemsRequireEnchantingForDurability( + GameTestHelper helper + ) { + Set expectedDiamondEquipment = Set.of( + Items.DIAMOND_SWORD, + Items.DIAMOND_SHOVEL, + Items.DIAMOND_PICKAXE, + Items.DIAMOND_AXE, + Items.DIAMOND_HOE, + Items.DIAMOND_SPEAR, + Items.DIAMOND_HELMET, + Items.DIAMOND_CHESTPLATE, + Items.DIAMOND_LEGGINGS, + Items.DIAMOND_BOOTS, + Items.DIAMOND_HORSE_ARMOR, + Items.DIAMOND_NAUTILUS_ARMOR + ); + Set enchantableDiamondItems = BuiltInRegistries.ITEM.stream() + .filter(item -> { + Identifier id = BuiltInRegistries.ITEM.getKey(item); + return id.getNamespace().equals("minecraft") + && id.getPath().startsWith("diamond_") + && item.getDefaultInstance().isEnchantable(); + }) + .collect(Collectors.toUnmodifiableSet()); + helper.assertValueEqual( + enchantableDiamondItems, + expectedDiamondEquipment, + "The durability policy must enumerate every enchantable Diamond item" + ); + + Holder unbreaking = + helper.getLevel() + .registryAccess() + .lookupOrThrow(Registries.ENCHANTMENT) + .getOrThrow(Enchantments.UNBREAKING); + for (Item item : expectedDiamondEquipment) { + ItemStack stack = item.getDefaultInstance(); + int fullDurability = stack.getOrDefault( + DataComponents.MAX_DAMAGE, + 0 + ); + helper.assertTrue( + fullDurability > 0, + item + " must have a full durability component" + ); + + int fragileDurability = stack.is( + RetoldTags.FRAGILE_UNENCHANTED_DIAMOND_TOOLS + ) + ? RetoldDiamondDurability.UNENCHANTED_TOOL_DURABILITY + : RetoldDiamondDurability.fragileArmorDurability( + fullDurability + ); + helper.assertValueEqual( + stack.getMaxDamage(), + fragileDurability, + item + " must begin with fragile unenchanted durability" + ); + + stack.enchant(unbreaking, 1); + helper.assertValueEqual( + stack.getMaxDamage(), + fullDurability, + item + " must regain full durability when enchanted" + ); + stack.set(DataComponents.ENCHANTMENTS, ItemEnchantments.EMPTY); + helper.assertValueEqual( + stack.getMaxDamage(), + fragileDurability, + item + " must become fragile after removing enchantments" + ); + } + + var attacker = helper.spawn(EntityTypes.ZOMBIE, 1, 2, 1); + attacker.setNoAi(true); + var horse = helper.spawn(EntityTypes.HORSE, 2, 2, 1); + var nautilus = helper.spawn(EntityTypes.NAUTILUS, 3, 2, 1); + horse.setItemSlot( + EquipmentSlot.BODY, + new ItemStack(Items.DIAMOND_HORSE_ARMOR) + ); + nautilus.setItemSlot( + EquipmentSlot.BODY, + new ItemStack(Items.DIAMOND_NAUTILUS_ARMOR) + ); + + var damageSource = helper.getLevel().damageSources().mobAttack(attacker); + horse.hurtServer(helper.getLevel(), damageSource, 8.0F); + nautilus.hurtServer(helper.getLevel(), damageSource, 8.0F); + helper.assertTrue( + horse.getItemBySlot(EquipmentSlot.BODY).getDamageValue() > 0, + "Diamond Horse Armor must lose durability from protected hits" + ); + helper.assertTrue( + nautilus.getItemBySlot(EquipmentSlot.BODY).getDamageValue() > 0, + "Diamond Nautilus Armor must lose durability from protected hits" + ); + + helper.succeed(); } private static void copperGenerationIsReduced(GameTestHelper helper) { diff --git a/src/main/resources/data/retold/tags/item/fragile_unenchanted_diamond_armor.json b/src/main/resources/data/retold/tags/item/fragile_unenchanted_diamond_armor.json index 8d80860..8347736 100644 --- a/src/main/resources/data/retold/tags/item/fragile_unenchanted_diamond_armor.json +++ b/src/main/resources/data/retold/tags/item/fragile_unenchanted_diamond_armor.json @@ -3,6 +3,8 @@ "minecraft:diamond_helmet", "minecraft:diamond_chestplate", "minecraft:diamond_leggings", - "minecraft:diamond_boots" + "minecraft:diamond_boots", + "minecraft:diamond_horse_armor", + "minecraft:diamond_nautilus_armor" ] } From dc73642b21c78b14eca5b9ef39f87e02284e1f91 Mon Sep 17 00:00:00 2001 From: xefensor Date: Wed, 12 Aug 2026 01:15:23 +0200 Subject: [PATCH 05/11] Complete progression alternatives and spears --- CHANGELOG.md | 8 +- docs/internal/design_implementation_status.md | 9 +- docs/internal/enchanting_design.md | 5 +- docs/internal/retold_design_risks.md | 2 +- docs/internal/retold_mod_system.md | 15 +- docs/internal/retold_roadmap.md | 4 +- docs/internal/tool_armor_ore_progression.md | 13 +- .../retold/gametest/RetoldGameTests.java | 2 + .../RetoldLeafStickLootModifier.java | 27 +- ...RetoldProgressionAcquisitionGameTests.java | 375 ++++++++++++++++++ .../RetoldToolProgressionGameTests.java | 139 ++++++- .../retold/registry/RetoldBlocks.java | 32 ++ .../registry/RetoldCreativeModeTabs.java | 4 +- .../xefensor/retold/registry/RetoldTags.java | 8 + .../assets/retold/items/flint_spear.json | 25 ++ .../assets/retold/items/steel_spear.json | 25 ++ .../resources/assets/retold/lang/en_us.json | 2 + .../loot_table/chests/spawn_bonus_chest.json | 205 ++++++++++ .../chests/village/village_armorer.json | 88 ++++ .../chests/village/village_toolsmith.json | 107 +++++ .../chests/village/village_weaponsmith.json | 156 ++++++++ .../tags/enchantment/on_random_loot.json | 9 + .../minecraft/tags/enchantment/tradeable.json | 9 + .../data/minecraft/tags/item/spears.json | 6 + .../tags/villager_trade/armorer/level_1.json | 6 + .../tags/villager_trade/armorer/level_2.json | 10 + .../tags/villager_trade/armorer/level_3.json | 9 + .../tags/villager_trade/armorer/level_4.json | 10 + .../tags/villager_trade/armorer/level_5.json | 12 + .../villager_trade/toolsmith/level_1.json | 6 + .../villager_trade/toolsmith/level_2.json | 10 + .../villager_trade/toolsmith/level_3.json | 7 + .../villager_trade/toolsmith/level_4.json | 11 + .../villager_trade/toolsmith/level_5.json | 12 + .../villager_trade/weaponsmith/level_1.json | 6 + .../villager_trade/weaponsmith/level_2.json | 9 + .../villager_trade/weaponsmith/level_3.json | 7 + .../villager_trade/weaponsmith/level_4.json | 10 + .../villager_trade/weaponsmith/level_5.json | 11 + .../emerald_enchanted_iron_pickaxe.json | 37 ++ .../data/retold/recipe/flint_spear.json | 16 + .../data/retold/recipe/steel_spear.json | 16 + .../block/stick_dropping_living_bushes.json | 8 + .../retold/villager_teaching/weaponsmith.json | 24 ++ .../progression/copper_axe.json | 12 + .../progression/copper_boots.json | 12 + .../progression/copper_chestplate.json | 12 + .../progression/copper_helmet.json | 12 + .../progression/copper_hoe.json | 12 + .../progression/copper_leggings.json | 12 + .../progression/copper_pickaxe.json | 12 + .../progression/copper_shovel.json | 12 + .../progression/copper_spear.json | 12 + .../progression/copper_sword.json | 12 + .../progression/diamond_axe.json | 12 + .../progression/diamond_boots.json | 12 + .../progression/diamond_chestplate.json | 12 + .../progression/diamond_helmet.json | 12 + .../progression/diamond_hoe.json | 12 + .../progression/diamond_leggings.json | 12 + .../progression/diamond_pickaxe.json | 12 + .../progression/diamond_shovel.json | 12 + .../progression/diamond_spear.json | 12 + .../progression/diamond_sword.json | 12 + .../progression/enchanted_diamond_axe.json | 38 ++ .../progression/enchanted_diamond_boots.json | 38 ++ .../enchanted_diamond_chestplate.json | 38 ++ .../enchanted_diamond_pickaxe.json | 38 ++ .../progression/enchanted_diamond_spear.json | 38 ++ .../progression/enchanted_diamond_sword.json | 38 ++ .../villager_trade/progression/iron_axe.json | 12 + .../progression/iron_boots.json | 12 + .../progression/iron_chestplate.json | 12 + .../progression/iron_helmet.json | 12 + .../villager_trade/progression/iron_hoe.json | 12 + .../progression/iron_leggings.json | 12 + .../progression/iron_pickaxe.json | 12 + .../progression/iron_shovel.json | 12 + .../progression/iron_spear.json | 12 + .../progression/iron_sword.json | 12 + 80 files changed, 2067 insertions(+), 33 deletions(-) create mode 100644 src/main/java/cz/xefensor/retold/progression/RetoldProgressionAcquisitionGameTests.java create mode 100644 src/main/resources/assets/retold/items/flint_spear.json create mode 100644 src/main/resources/assets/retold/items/steel_spear.json create mode 100644 src/main/resources/data/minecraft/loot_table/chests/spawn_bonus_chest.json create mode 100644 src/main/resources/data/minecraft/loot_table/chests/village/village_armorer.json create mode 100644 src/main/resources/data/minecraft/loot_table/chests/village/village_toolsmith.json create mode 100644 src/main/resources/data/minecraft/loot_table/chests/village/village_weaponsmith.json create mode 100644 src/main/resources/data/minecraft/tags/enchantment/on_random_loot.json create mode 100644 src/main/resources/data/minecraft/tags/enchantment/tradeable.json create mode 100644 src/main/resources/data/minecraft/tags/item/spears.json create mode 100644 src/main/resources/data/minecraft/tags/villager_trade/armorer/level_1.json create mode 100644 src/main/resources/data/minecraft/tags/villager_trade/armorer/level_2.json create mode 100644 src/main/resources/data/minecraft/tags/villager_trade/armorer/level_3.json create mode 100644 src/main/resources/data/minecraft/tags/villager_trade/armorer/level_4.json create mode 100644 src/main/resources/data/minecraft/tags/villager_trade/armorer/level_5.json create mode 100644 src/main/resources/data/minecraft/tags/villager_trade/toolsmith/level_1.json create mode 100644 src/main/resources/data/minecraft/tags/villager_trade/toolsmith/level_2.json create mode 100644 src/main/resources/data/minecraft/tags/villager_trade/toolsmith/level_3.json create mode 100644 src/main/resources/data/minecraft/tags/villager_trade/toolsmith/level_4.json create mode 100644 src/main/resources/data/minecraft/tags/villager_trade/toolsmith/level_5.json create mode 100644 src/main/resources/data/minecraft/tags/villager_trade/weaponsmith/level_1.json create mode 100644 src/main/resources/data/minecraft/tags/villager_trade/weaponsmith/level_2.json create mode 100644 src/main/resources/data/minecraft/tags/villager_trade/weaponsmith/level_3.json create mode 100644 src/main/resources/data/minecraft/tags/villager_trade/weaponsmith/level_4.json create mode 100644 src/main/resources/data/minecraft/tags/villager_trade/weaponsmith/level_5.json create mode 100644 src/main/resources/data/minecraft/villager_trade/wandering_trader/emerald_enchanted_iron_pickaxe.json create mode 100644 src/main/resources/data/retold/recipe/flint_spear.json create mode 100644 src/main/resources/data/retold/recipe/steel_spear.json create mode 100644 src/main/resources/data/retold/tags/block/stick_dropping_living_bushes.json create mode 100644 src/main/resources/data/retold/villager_trade/progression/copper_axe.json create mode 100644 src/main/resources/data/retold/villager_trade/progression/copper_boots.json create mode 100644 src/main/resources/data/retold/villager_trade/progression/copper_chestplate.json create mode 100644 src/main/resources/data/retold/villager_trade/progression/copper_helmet.json create mode 100644 src/main/resources/data/retold/villager_trade/progression/copper_hoe.json create mode 100644 src/main/resources/data/retold/villager_trade/progression/copper_leggings.json create mode 100644 src/main/resources/data/retold/villager_trade/progression/copper_pickaxe.json create mode 100644 src/main/resources/data/retold/villager_trade/progression/copper_shovel.json create mode 100644 src/main/resources/data/retold/villager_trade/progression/copper_spear.json create mode 100644 src/main/resources/data/retold/villager_trade/progression/copper_sword.json create mode 100644 src/main/resources/data/retold/villager_trade/progression/diamond_axe.json create mode 100644 src/main/resources/data/retold/villager_trade/progression/diamond_boots.json create mode 100644 src/main/resources/data/retold/villager_trade/progression/diamond_chestplate.json create mode 100644 src/main/resources/data/retold/villager_trade/progression/diamond_helmet.json create mode 100644 src/main/resources/data/retold/villager_trade/progression/diamond_hoe.json create mode 100644 src/main/resources/data/retold/villager_trade/progression/diamond_leggings.json create mode 100644 src/main/resources/data/retold/villager_trade/progression/diamond_pickaxe.json create mode 100644 src/main/resources/data/retold/villager_trade/progression/diamond_shovel.json create mode 100644 src/main/resources/data/retold/villager_trade/progression/diamond_spear.json create mode 100644 src/main/resources/data/retold/villager_trade/progression/diamond_sword.json create mode 100644 src/main/resources/data/retold/villager_trade/progression/enchanted_diamond_axe.json create mode 100644 src/main/resources/data/retold/villager_trade/progression/enchanted_diamond_boots.json create mode 100644 src/main/resources/data/retold/villager_trade/progression/enchanted_diamond_chestplate.json create mode 100644 src/main/resources/data/retold/villager_trade/progression/enchanted_diamond_pickaxe.json create mode 100644 src/main/resources/data/retold/villager_trade/progression/enchanted_diamond_spear.json create mode 100644 src/main/resources/data/retold/villager_trade/progression/enchanted_diamond_sword.json create mode 100644 src/main/resources/data/retold/villager_trade/progression/iron_axe.json create mode 100644 src/main/resources/data/retold/villager_trade/progression/iron_boots.json create mode 100644 src/main/resources/data/retold/villager_trade/progression/iron_chestplate.json create mode 100644 src/main/resources/data/retold/villager_trade/progression/iron_helmet.json create mode 100644 src/main/resources/data/retold/villager_trade/progression/iron_hoe.json create mode 100644 src/main/resources/data/retold/villager_trade/progression/iron_leggings.json create mode 100644 src/main/resources/data/retold/villager_trade/progression/iron_pickaxe.json create mode 100644 src/main/resources/data/retold/villager_trade/progression/iron_shovel.json create mode 100644 src/main/resources/data/retold/villager_trade/progression/iron_spear.json create mode 100644 src/main/resources/data/retold/villager_trade/progression/iron_sword.json diff --git a/CHANGELOG.md b/CHANGELOG.md index d3f3b37..b1ccecc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,9 +11,11 @@ Each release should be readable in two passes: ### Player-Facing -- The survival opening now begins with Sticks and Flint instead of punching logs. Leaves have an additional 20% chance to drop 1–2 Sticks, increasing by five percentage points per Fortune level; shears and Silk Touch retain their normal leaf-block harvest without the extra drop. Logs require a suitable tool, the 2x2 Flint Multi-tool harvests the first wood, exposed Copper, and soft early stone, and vanilla Wooden and Stone tool recipes no longer bypass the material ladder. Copper generation now makes six vein attempts per chunk instead of sixteen while preserving normal vein sizes, reducing cave-wall clutter without making each discovery unrewarding. Copper Pickaxes can harvest normal Stone for Cobblestone, but do so at 25% speed until Iron makes ordinary mining practical. +- The survival opening now begins with Sticks and Flint instead of punching logs. Leaves have an additional 20% chance to drop 1–2 Sticks, increasing by five percentage points per Fortune level; Dead Bushes drop 2–4 Sticks, while living Bush, Firefly Bush, Rose Bush, and Sweet Berry Bush blocks have a 10% chance to drop one. Shears and Silk Touch preserve the relevant blocks without extra Sticks. Logs require a suitable tool, the 2x2 Flint Multi-tool harvests the first wood, exposed Copper, and soft early stone, and vanilla Wooden and Stone tool recipes no longer bypass the material ladder. Copper generation now makes six vein attempts per chunk instead of sixteen while preserving normal vein sizes, reducing cave-wall clutter without making each discovery unrewarding. Copper Pickaxes can harvest normal Stone for Cobblestone, but do so at 25% speed until Iron makes ordinary mining practical. - Campfires are now crafted from three Sticks and three Logs without Coal or Flint and begin unlit immediately when placed, without briefly flashing their lit appearance. Using a bare Flint lights one and consumes that Flint in Survival, while Flint and Steel retains its normal durability-based ignition. Clay Balls fire into Bricks on a Campfire; eight Bricks in a ring then craft the Brick Furnace, Retold's renamed Smoker. It keeps food cooking, makes Charcoal from burnable logs, and processes Raw Copper and both Copper ores so players can reach Copper before obtaining Cobblestone for a normal Furnace. -- Blast Furnaces now process Iron Ingots directly into Steel Ingots using any ordinary fuel. Steel provides a full Pickaxe, Axe, Shovel, Hoe, Sword, and armor tier between Iron and Diamond. Copper and Iron remain painfully slow on Deepslate-family blocks, while Steel restores full deep-mining speed, harvests deep Diamond Ore, and still leaves Obsidian to Diamond. +- Blast Furnaces now process Iron Ingots directly into Steel Ingots using any ordinary fuel. The Spear now follows Flint, Copper, Iron, Steel, and Diamond progression, with new Flint and Steel Spears using provisional Stone and Iron visuals. Steel provides a full Pickaxe, Axe, Shovel, Hoe, Sword, Spear, and armor tier between Iron and Diamond. Copper and Iron remain painfully slow on Deepslate-family blocks, while Steel restores full deep-mining speed, harvests deep Diamond Ore, and still leaves Obsidian and Ancient Debris to Diamond. +- Alternative equipment acquisition now follows fixed world rules in single-player and multiplayer. Bonus chests provide one Flint Multi-tool instead of Wooden/Stone tools; safe Village smith chests stop at Copper equipment and at most two Iron Ingots. Smith equipment trades unlock Copper at Apprentice for 8–12 Emeralds, Iron at Expert for 24–32, and Diamond at Master for 48–64, with enchanted Diamond offers rarer than unenchanted ones. The Wandering Trader retains its rare enchanted Iron Pickaxe at an enchantment-adjusted price around 48 Emeralds. +- Mending can no longer be newly generated by Librarian trades or random loot. Existing Mending items continue to function, and commands and Creative mode retain the enchantment. - Unenchanted Diamond tools and Spears now have only 64 durability, while unenchanted Diamond armor has leather-like 6x durability. Diamond Horse and Nautilus Armor now use 96 durability before enchanting and 528 afterward, and lose durability from real hits like other armor. Any enchantment immediately restores full Diamond durability; removing every enchantment makes the item fragile again. A heavily damaged item stripped beyond that fragile limit retains one final use instead of becoming invalid immediately. - Wolf Armor and every Horse and Nautilus Armor material can now be enchanted with the same enchantment pool as a Chestplate. Each uses the enchanting value of its own armor material. Protection enchantments now affect damage absorbed by Wolf Armor as well as ordinary animal health damage; Fire Protection also retains its normal shorter-burning effect. - The End no longer produces its periodic celestial flashes, temporary brightness pulses, or delayed flash sounds. Retold's generated End sky remains unchanged. @@ -25,7 +27,7 @@ Each release should be readable in two passes: ### Technical -- Added the 48-durability Flint Multi-tool and provisional Steel material with data-driven mining, repair, common-ingot, enchantment-family, and armor tags. A global loot modifier supplies additional Sticks from every block in `minecraft:leaves`, and placed-feature overrides reduce both ordinary and Dripstone Copper attempts from sixteen to six per chunk. Exact Wooden/Stone recipes are removed during recipe loading; Armorer, Toolsmith, and Weaponsmith lessons follow the material ladder. Five focused GameTests cover leaf Stick supply, reduced Copper placement across seeded chunk-border samples, the unfueled Campfire recipe and ignition behavior, harvest tiers through Steel, Copper/Deepslate pacing, starter and equipment crafting, Brick Furnace processing, normal Iron-to-Steel blasting, and Furnace availability. +- Added the 48-durability Flint Multi-tool, Flint Spear, and provisional Steel material with data-driven mining, repair, common-ingot, Spear, enchantment-family, and armor tags. A global loot modifier supplies scaled Sticks from leaves and woody bushes, and placed-feature overrides reduce both ordinary and Dripstone Copper attempts from sixteen to six per chunk. Data-driven chest and Villager-trade overrides enforce fixed acquisition tiers without per-player state, while enchantment tags remove Mending from new trade/random-loot generation. Exact Wooden/Stone recipes are removed during recipe loading; Armorer, Toolsmith, and Weaponsmith lessons follow the material ladder. Focused GameTests cover scaled Stick supply, acquisition tables and prices, Mending source removal, reduced Copper placement, Campfire behavior, harvest tiers, Spear/starter/equipment crafting, station processing, and Furnace availability. - Added tag-driven dynamic Diamond durability through a narrow `ItemStack.getMaxDamage` hook and a named progression policy. Diamond Horse and Nautilus Armor receive a 528-durability component and server-side BODY-slot wear from non-bypassing hits. Focused coverage enumerates all twelve enchantable Diamond items and verifies fragile values, enchantment restoration, removal regression, real animal-armor wear, vanilla-tag preservation, and the over-damaged stripped-item safeguard. - Added data-driven Chestplate enchantment compatibility and material-matched enchantability components for all twelve vanilla animal armors. A Wolf-specific incoming-damage bridge applies vanilla enchantment protection before Wolf Armor's special durability-absorption path bypasses ordinary living-entity mitigation. Focused coverage verifies every supported-enchantment set plus equipped Protection-family mitigation, Fire Protection burn duration, Thorns, Unbreaking, Mending, Binding, and Vanishing behavior across Wolf, Horse, and Nautilus armor paths. - Added a client-only vanilla-End hook that clears `EndFlashState` after level construction, suppressing all flash rendering, lightmap, and sound paths while preserving the End skybox and leaving other End-style dimensions untouched. diff --git a/docs/internal/design_implementation_status.md b/docs/internal/design_implementation_status.md index 14f926b..76f71a4 100644 --- a/docs/internal/design_implementation_status.md +++ b/docs/internal/design_implementation_status.md @@ -162,11 +162,11 @@ Largest missing or partial design areas: | Design item | Status | Current implementation | | --- | --- | --- | -| Leaves provide opening Sticks | Implemented / needs in-game verification | Every block in `minecraft:leaves` receives an additional 20% chance for 1–2 Sticks, with +5 percentage points per Fortune level. Shears and Silk Touch are excluded. A focused real-loot-table GameTest samples the increased base supply, Fortune III improvement, and both harvest exclusions; natural decay, explosions, modded leaves, and first-spawn pacing remain to be verified in-game. | +| Leaves and bushes provide opening Sticks | Implemented / needs in-game verification | Every block in `minecraft:leaves` receives an additional 20% chance for 1–2 Sticks, with +5 percentage points per Fortune level. Dead Bushes drop 2–4, while Bush, Firefly Bush, Rose Bush, and Sweet Berry Bush receive a 10% one-Stick roll. Shears and Silk Touch are excluded. A focused real-loot-table GameTest samples the distributions and harvest exclusions; natural decay, explosions, modded leaves, bush farming, and first-spawn pacing remain to be verified in-game. | | Wood cannot be obtained by hand | Implemented / needs in-game verification | A harvest check prevents logs from dropping unless the held item is a correct harvesting tool. Focused GameTest coverage verifies hand denial and Flint Multi-tool success; naturally verify block breaking, drops, Adventure mode, and common modded logs. | | Flint multi-tool | Implemented / needs in-game verification | The 2x2 two-Flint/one-Stick recipe, 48-durability combined axe/shovel/primitive Copper tool, repair tag, creative placement, language entry, and provisional vanilla-Flint model are implemented. Focused GameTests verify the recipe, durability, logs, normal Copper Ore, Tuff, and Stone denial. Natural survival pacing and visuals remain unverified. | | Reduced Copper generation | Implemented / needs fresh-world verification | Both `minecraft:ore_copper` and `minecraft:ore_copper_large` now make six placement attempts per chunk instead of sixteen, a 62.5% frequency reduction. Vanilla size-10 ordinary and size-20 Dripstone veins plus their height distribution are preserved. A focused registry-backed GameTest verifies both loaded overrides across three seeded origins spanning a chunk border; several fresh seeds, cave-wall exposure, and existing-versus-new chunk behavior still need natural verification. | -| Flint/copper/iron/steel/diamond tool progression | Partial / needs verification | Progression is implemented through Diamond: Wooden/Stone recipes are removed, Copper and Steel geology pacing is active, and unenchanted tagged Diamond tools/Spear use 64 durability while any enchantment restores their vanilla maximum. Removing every enchantment makes them fragile again. Focused tests cover the boundaries and transitions. Netherite/Aenderite equipment and final balance remain incomplete. | +| Flint/copper/iron/steel/diamond tool progression | Partial / needs verification | Progression is implemented through Diamond: Wooden/Stone recipes are removed, Copper and Steel geology pacing is active, Spears now follow Flint/Copper/Iron/Steel/Diamond, and unenchanted tagged Diamond tools/Spear use 64 durability while any enchantment restores their vanilla maximum. Removing every enchantment makes them fragile again. Focused tests cover the boundaries, Spear recipes/tags, and transitions. Netherite/Aenderite equipment and final balance remain incomplete. | | Campfire, Brick Furnace, Furnace, Blast Furnace, and parallel enchanting progression | Partial / needs verification | Campfires use a fuel-free three-Stick/three-Log recipe. Their initial placement state is unlit on both logical sides, avoiding the former client-visible lit-state flash. Bare Flint ignites one and is consumed in Survival; Flint and Steel retains normal durability use. Campfire cooking fires Clay Balls into Bricks, and eight Bricks craft the Smoker-backed Brick Furnace. The Brick and normal Furnace roles are implemented. Per the 2026-08-11 choice, a standard 100-tick blasting recipe converts one Iron Ingot to one Steel Ingot while accepting ordinary Blast Furnace fuels; Charcoal is valid but not mandatory or fixed 1:1. Blast Furnace construction remains vanilla. Enchanting follows the separate deterministic SGA system. | | Leather/copper/iron/steel/diamond armor progression | Partial / needs verification | Steel has its provisionally balanced four-piece set. Unenchanted Diamond player armor uses 6x durability (66/96/90/78), while any enchantment restores 33x durability and removing all enchantments restores fragility. Diamond Horse and Nautilus Armor now follow the BODY/Chestplate 96/528 durability transition and take wear from real hits; non-Diamond animal armor remains indestructible. All twelve Wolf, Horse, and Nautilus Armor items support the exact Chestplate enchantment set and use their material's enchantability value. Focused equipped-animal tests cover damage wear, Protection-family mitigation, Fire Protection burn duration, Thorns, Unbreaking, Mending, Binding, and Vanishing paths. Retold bridges protection into Wolf Armor's special absorbed-durability path, while Horse and Nautilus armor use vanilla health mitigation. Later Retold armor tiers remain incomplete. | | Diamond tools weak unless enchanted | Implemented / needs in-game verification | A narrow `ItemStack` hook delegates to `RetoldDiamondDurability`; all twelve enchantable Diamond items use fragile unenchanted durability and their full maximum while enchanted. Stripping a heavily damaged item preserves its damage and leaves one final use rather than an invalid stack. Focused coverage enumerates the complete set, verifies enchant/remove transitions and the damaged-item edge case, and confirms Diamond Horse/Nautilus Armor wear on real hits. | @@ -175,12 +175,12 @@ Largest missing or partial design areas: | Iron rods/sticks crafting changes | Not implemented | | Scaffolding crafted with wooden sticks / normal wood | Not implemented | | Glass dyeing max 8 but supports fewer | Not implemented | -| Flint spear | Not implemented | +| Flint and Steel spears | Implemented / provisional visuals | Both use the standard diagonal one-point/two-Stick recipe and their tier durability. Flint temporarily references Stone Spear visuals and Steel references Iron Spear visuals. Focused crafting/tag coverage passes; natural combat, animation, enchanting, and repair behavior need verification. | | Boats/minecart crafting variants | Not implemented | | Sword blocking / shield combat rework | Not implemented | | Sword sweep on right-click | Not implemented | | XP/energy affects damage/defense | Not implemented | -| Remove mending | Not implemented | +| Remove new Mending acquisition | Implemented / needs natural verification | Mending is excluded from `minecraft:tradeable` and `minecraft:on_random_loot`, removing new Librarian and random-loot generation. It remains registered for commands/Creative and continues functioning on existing items. Focused registry-tag coverage passes; naturally verify fishing, structure loot, Librarians, existing worlds, and datapack compatibility. | | Smithing table removed/merged with anvil | Not implemented | ## Recipe Discovery And Villagers @@ -195,6 +195,7 @@ Largest missing or partial design areas: | Librarian tells ingredients | Not implemented | Teaching unlocks recipes; ingredient explanation not found. | | Villagers magical pacifists lore | Design only / partial | Villager teaching and golem/illager lore support. No full villager society simulation. | | Villagers refresh trades every day | Implemented / needs in-game verification | `RetoldVillagerTradeRefresh` guarantees one refresh of existing professional-adult Villager offers when the Overworld day advances. It resets stock uses and updates demand without rerolling offers, professions, teaching data, or special map trades; Wandering Traders remain independent. The per-villager day marker persists through saves, and a GameTest covers first observation, same-day exhaustion, next-day refresh, and offer identity. | +| Equipment alternatives respect material progression | Implemented / needs natural and existing-world verification | Fixed server datapack rules apply identically in single-player and multiplayer: bonus chests supply a Flint Multi-tool, safe Village smith chests stop at Copper equipment and at most two Iron Ingots, and Armorer/Toolsmith/Weaponsmith equipment unlocks at Apprentice Copper (8–12 Emeralds), Expert Iron (24–32), and Master Diamond (48–64) with rarer enchanted variants. The Wandering Trader retains an enchanted Iron Pickaxe averaging roughly 48 Emeralds. Focused live-registry and sampled-loot coverage passes. Existing saved Villager offers are not rerolled; naturally verify profession leveling, discounts, restocking, interfaces, multiplayer, and new versus existing worlds. | | Villagers relight village torches | Implemented / needs in-game verification | In every stage, `RetoldVillagerTorchRelighting` lets an adult Villager restore one dry weather-extinguished normal, soul, or copper floor/wall torch within eight horizontal/five vertical blocks and within 32 blocks of remembered or live village context. Most professions stop, face, and use a one-second ranged magical cast. Nitwits cannot cast: during eligible idle/play time they path to a supported adjacent cell and visibly use a temporary Flint and Steel which never enters inventory and consumes no item or durability. Active physical use receives lightweight per-tick updates so the visual tool remains held for the full interaction; idle search and travel keep the normal dispatcher cadence. Both methods preserve wall facing, require `mobGriefing`, and yield to hunger, danger, targets, sleep, trading, incompatible activity, and higher ownership. Discovery reuses `TorchWeatherEvents`' loaded-chunk extinguished index, shared block-search/path budgets, LOD cooldowns, and a bounded physical-route timeout. Three focused GameTests and the extinguished-drop regression pass; the affected Villager TPS test peaks at 7.102 ms/tick. Natural Nitwit routing, rain, visual casting, crowded-village, save/reload, multiplayer, dedicated-server, and existing-world behavior remain unverified. | | Villages angered by stealing/crops/animals | Implemented / needs broader natural verification | Generated `chests/village/*` loot and future Farmer/Villager-controlled deposits carry exact persisted village-owned quantities. Player deposits remain unowned and leave first. Crops newly planted or replanted by vanilla Farmers carry separately persisted position ownership through growth; player planting clears it. Livestock becomes village-owned only after an assigned Villager profession actually feeds it. Offspring of two owned parents inherit village ownership; automatic offspring of an unowned player-associated parent inherit player protection. Witnessed mature harvest applies minor theft gossip, immature breaking or trampling applies stronger vandalism, and directly killing owned livestock in Survival applies `-50` reputation. Breaking protected storage remains severe enough for immediate vanilla Iron Golem hostility. Creative and Spectator players are ignored, and ambiguous existing-world storage, crops, and animals are not retroactively claimed. `/retold village status` summarizes the executing player's nearby per-Villager vanilla reputation and hostility risk. Four container/status, four crop, and four livestock GameTests cover persistence, provenance, the real vanilla Farmer hook, player protection, offenses, witnesses, Creative exclusion, aggregation, and thresholds. Natural save/reload, complete Farmer cycles, unusual farm/storage layouts, transported animals, multiplayer, dedicated-server, and existing-world checks remain unverified. | diff --git a/docs/internal/enchanting_design.md b/docs/internal/enchanting_design.md index 00ff783..1416c43 100644 --- a/docs/internal/enchanting_design.md +++ b/docs/internal/enchanting_design.md @@ -139,8 +139,9 @@ patterns that players can deduce. | Mending | item | restore | general | LSJ | | Curse of Vanishing | item | bind | undead | LCV | -Mending remains mapped while it is registered. Its separate planned removal will remove the spell -definition at the same time rather than leaving an unrenderable registry entry. +Mending remains mapped because the enchantment stays registered for existing items, commands, and +Creative testing. Retold removes it only from new random-loot and Librarian-trade selection, so an +existing Mending item remains renderable and functional. The important rule is that enchantments are semi-compositional. Shared meanings should produce shared glyphs instead of every enchantment being an unrelated code. diff --git a/docs/internal/retold_design_risks.md b/docs/internal/retold_design_risks.md index 24d7b6c..1a3246c 100644 --- a/docs/internal/retold_design_risks.md +++ b/docs/internal/retold_design_risks.md @@ -33,7 +33,7 @@ | Villages | Container, Farmer-crop, and profession-tended livestock offenses use witnessed vanilla gossip. Sight and village-context checks can be sensitive to walls, crowded settlements, vertical farms, merged double chests, animal transport, automation, and multiplayer timing. | Generated village loot plus Villager-produced quantities are protected; player deposits and ambiguous already-opened existing-world contents are not. Farmer planting/replanting marks persistent crop positions. Shepherds, Leatherworkers, and Butchers claim only animals they successfully feed with two real storage items; player interaction/leashing marks previously unowned livestock as player-associated. Offspring of two owned parents inherit persisted village ownership, while an automatic offspring of a player-associated unowned parent inherits player protection. Witnessed direct Survival kills add `-50`; monsters, environment, Creative, and Spectator do not. Four focused animal tests plus the crop/container groups cover persistence, ownership separation, conservation, offense strengths, witnesses, and exclusions; the latest 50-Villager TPS peak is 6.864 ms/tick. Naturally verify physical storage-to-pen routes, wandering/boat-transport edge cases, full harvest/replant cycles, trade prices, golem reaction, double chests, hoppers, simultaneous players, dedicated servers, and existing worlds before calling the loop fully verified. | | Stage 3 | Raid creation is now gated to Stage 3, but the broader illager behavior may need clearer player-facing feedback later. | Avoid major raid redesign without developer approval. The Stage 2 live creation rejection and Witch/Illager same-raid cooperation are regression-tested; natural Bad Omen preservation, Stage 3 Raid Omen conversion, wave participation, healing, and raid-exit behavior still need in-game verification. Existing raids deliberately continue if an administrative command moves the world back below Stage 3. | | Piglins | Stage 3 piglin/pigman hiring or follower behavior is planned but not implemented. | Needs feature design. | -| Items | The implemented Flint-through-Diamond spine changes first-spawn assumptions, leaf loot, Copper distribution, Campfire ignition, recipes, station use, mining speed, nine Steel equipment items, animal-armor enchanting, and the effective maximum durability of existing Diamond equipment. Its provisional balance, fuel economy, compatibility, and reused visuals need validation. Later equipment, mending removal, and combat reworks remain planned. | Focused GameTests cover the material ladder through Steel, six-attempt ordinary/large Copper placement across seeded chunk-border origins while retaining vanilla vein sizes, the 20% supplemental 1–2 Stick leaf roll and its Fortune/shears/Silk Touch boundaries, the fuel-free Campfire recipe, the real unlit initial placement-state hook, consumable bare-Flint ignition, durable Flint and Steel ignition, Clay-to-Brick campfire cooking, and the eight-Brick furnace boundary, plus all twelve enchantable Diamond items' dynamic durability, enchant/remove transitions, the heavily damaged stripped-item edge case, real Diamond Horse/Nautilus Armor wear, all twelve animal armors' exact Chestplate enchantment compatibility, and equipped-animal Protection-family, fire-duration, Thorns, durability, Mending, and curse paths. Wolf Armor's special absorption path applies vanilla enchantment protection before converting damage into durability loss; Fire Protection remains damage/duration reduction rather than immunity. Diamond Horse and Nautilus Armor now use 96/528 durability, while non-Diamond variants remain indestructible. The Copper override affects only newly generated chunks; naturally inspect multiple fresh seeds, ordinary and Dripstone caves, cave-wall exposure, chunk borders, early acquisition time, and datapack/worldgen-mod compatibility before further tuning. Visually verify that Campfire placement no longer flashes lit on the client, plus cooking four Clay items, water/extinguishing, Creative consumption exemption, automation, recipe-book presentation, multiplayer, and compatibility with Campfire/recipe mods. Also verify leaf breaking and decay, explosions, non-Oak and modded tagged leaves, first-spawn Stick pacing, and interaction with datapacks or other global loot modifiers before final tuning. Option 2 means any enchantment grants full Diamond durability, while removing all enchantments restores fragility; tagged tools/Spear use 64 unenchanted durability and player/body armor uses 6x. Existing unenchanted Diamond gear changes automatically after update. Naturally test crafting, table/anvil/loot/command enchantments, Grindstone removal, durability bars/tooltips, break timing, repair/Mending interactions, deaths/containers, multiple equipment types, multiplayer, dedicated servers, and existing worlds. A stripped over-cap item deliberately retains one final use. Naturally verify animal-armor combat behavior, enchanting-table/anvil/SGA presentation, death drops, and multiplayer despite focused automated coverage. Also measure Steel's ordinary-fuel economy and naturally verify its recipes/stats/repairs/enchanting/trims and reused Iron visuals. Aenderite still provides only an ore/raw/ingot foundation. | +| Items | The implemented Flint-through-Diamond spine changes first-spawn assumptions, leaf/bush loot, chest and Villager alternatives, Mending acquisition, Copper distribution, Campfire ignition, recipes, station use, mining speed, Flint/Steel Spears, ten Steel equipment items, animal-armor enchanting, and the effective maximum durability of existing Diamond equipment. Its provisional balance, fuel economy, compatibility, and reused visuals need validation. Later equipment and combat reworks remain planned. | Focused GameTests cover the material ladder through Steel, six-attempt ordinary/large Copper placement across seeded chunk-border origins, scaled leaf/Dead Bush/living-bush Stick rolls and harvest exclusions, Flint/Steel Spear recipes/tags, bonus and Village chest ceilings, mastery/price trade tiers, enchanted trade rarity, Wandering Trader pricing, Mending source tags, Campfire/Brick Furnace boundaries, all twelve enchantable Diamond items, and animal-armor enchant effects. Chest/trade/enchantment overrides are global server data and therefore consistent across players, but existing saved Villager offers are deliberately not rerolled and datapacks may replace the same tables/tags. Naturally verify new and existing worlds, Villager leveling/discounts/restocking, multiplayer/dedicated servers, every chest type, fishing and structure Mending absence, bush farming, Spear combat/repair/enchanting, reused visuals, fresh-seed Copper pacing, Campfire visuals/automation, Steel fuel economy, and dynamic Diamond durability. Existing Mending items remain functional, and commands/Creative retain access. Aenderite still provides only an ore/raw/ingot foundation. | | Environment | Death drops should despawn much later than vanilla, not never. | No implementation confirmed. | | Beds | Beds should not skip night; valid daytime bed rest is allowed when night skipping is disabled. | Healing behavior not confirmed implemented. | | Nether | Nether portal spread is planned as energy drain. | Needs bounded implementation design. | diff --git a/docs/internal/retold_mod_system.md b/docs/internal/retold_mod_system.md index 90ffe14..beec926 100644 --- a/docs/internal/retold_mod_system.md +++ b/docs/internal/retold_mod_system.md @@ -140,8 +140,9 @@ the Copper Pickaxe receives a Stone-specific speed penalty, Copper and Iron Pick Steel-tier Deepslate penalty, and exact vanilla Wooden/Stone tool recipes are removed during recipe JSON modification. `RetoldLeafStickLootModifier`, registered through `RetoldLootModifiers`, gives every `minecraft:leaves` block a supplemental 20% roll for 1–2 Sticks, increasing five percentage -points per Fortune level and excluding shears and Silk Touch. `RetoldBlocks` registers the Flint -Multi-tool and provisional Steel tool/armor materials, while block/item tags own mining, repair, +points per Fortune level. It also normalizes Dead Bushes to 2–4 Sticks and gives tagged living +bushes a 10% one-Stick roll, while excluding shears and Silk Touch. `RetoldBlocks` registers the +Flint Multi-tool, Flint Spear, Steel Spear, and provisional Steel tool/armor materials, while block/item tags own mining, repair, enchantment-family, and equipment boundaries. Vanilla placed-feature overrides reduce ordinary and Dripstone Copper from sixteen to six attempts per chunk while retaining vanilla vein sizes and height distribution; only newly generated chunks receive the reduced distribution. @@ -153,7 +154,11 @@ the three-Stick/three-Log Campfire, fire Clay Balls into Bricks through campfire the vanilla Smoker as the eight-Brick Brick Furnace, add its Copper/Charcoal processing, blast Iron Ingots directly into Steel, and craft the full standard Steel tool and armor sets. These rules are server-owned; client resources provide names and deliberately reference vanilla Flint/Iron models -until final art is approved. +until final art is approved. Vanilla chest, Villager-trade, and enchantment-tag overrides define +the same alternative-acquisition rules for every player: bonus chests stop at Flint, safe Village +smith chests stop at Copper gear, smith equipment tiers follow Villager mastery and expensive +Emerald ranges, and Mending is excluded from new random loot and Librarian selection. Existing +saved offers and existing Mending items are deliberately not rewritten. `RetoldDiamondDurability` owns the selected dynamic Diamond rule. `ItemStackDiamondDurabilityMixin` is only the return-value hook for `ItemStack.getMaxDamage`; separate item tags identify affected @@ -618,8 +623,8 @@ Data: - spell definitions load from `data//enchantment_spells/*.json` - definitions map an enchantment id to semantic `domain`, `effect`, and `modifier` identifiers -- 43 definitions cover every currently registered vanilla enchantment, including Mending while its - separately planned removal remains unimplemented +- 43 definitions cover every currently registered vanilla enchantment, including Mending because + it remains usable on existing and command/Creative-created items even though new acquisition is removed - the fixed 26-concept vocabulary maps one semantic concept to each built-in SGA A-Z glyph; definitions using unknown concepts are rejected with the rest of an invalid reload diff --git a/docs/internal/retold_roadmap.md b/docs/internal/retold_roadmap.md index 4b7f11c..bee9de7 100644 --- a/docs/internal/retold_roadmap.md +++ b/docs/internal/retold_roadmap.md @@ -39,9 +39,9 @@ These are the strongest next design-aligned areas: These are still planned but need feature-specific design before implementation: -- tool, armor, ore, and station progression beyond the implemented Flint-through-Diamond spine, six-attempt-per-chunk Copper frequency adjustment, and initial Aenderite material foundation; next naturally verify Copper density and the dynamic Diamond rule, then design remaining Netherite/Aenderite equipment boundaries +- tool, armor, ore, and station progression beyond the implemented Flint-through-Diamond spine, Spear ladder, alternative-acquisition tiers, six-attempt-per-chunk Copper frequency adjustment, and initial Aenderite material foundation; next naturally verify Copper density, loot/trade pacing, and the dynamic Diamond rule, then design remaining Netherite/Aenderite equipment boundaries - enchanting rework beyond the implemented complete 43-spell SGA catalog, knowledge persistence/sync, anvil-learning route, knowledge-aware tooltips, and deterministic glyph-entry table; next verify/refine the composed client layout and dedicated multiplayer synchronization, then perform the wider enchantment audit -- mending removal +- broader enchanting acquisition changes beyond the implemented removal of Mending from new random loot and Librarian trades - sword/shield combat rework - Stage 3 piglin/pigman hiring or follower behavior - Nether portal spread as portal energy draining surroundings diff --git a/docs/internal/tool_armor_ore_progression.md b/docs/internal/tool_armor_ore_progression.md index 241a346..462a868 100644 --- a/docs/internal/tool_armor_ore_progression.md +++ b/docs/internal/tool_armor_ore_progression.md @@ -305,8 +305,9 @@ Steel receives a full normal tool and armor set. It should be the strongest conventional Overworld workhorse material before Diamond becomes a magical progression step. The provisional tool material uses 750 durability, mining speed 7.0, attack bonus 2.5, and -enchantability 12. The implemented set contains Pickaxe, Axe, Shovel, Hoe, and Sword; nonstandard -weapons such as the Spear remain part of the later combat/tool audit. +enchantability 12. The implemented set contains Pickaxe, Axe, Shovel, Hoe, Sword, and Spear. The +Steel Spear follows an interpolated Iron-to-Diamond attack curve and temporarily references the +vanilla Iron Spear visuals. The provisional armor material uses durability multiplier 25, enchantability 12, toughness 1, and defenses of 3 Helmet, 7 Chestplate, 6 Leggings, and 3 Boots. Until a Steel art direction is @@ -534,6 +535,9 @@ Copper rate again only from concrete natural-world results. - The Flint Multi-tool is the primitive combined axe/shovel/pick-like starter tool. - The Flint Multi-tool recipe is exactly two Flint across the top and one Stick below the right-hand Flint in the 2x2 inventory grid. - Vanilla Wooden and Stone axe, hoe, pickaxe, shovel, spear, and sword recipes are removed so they cannot bypass Copper progression. +- Spears follow Flint, Copper, Iron, Steel, and Diamond; Gold remains an optional fast, fragile side grade. +- Bonus chests provide one Flint Multi-tool, safe Village smith chests stop at Copper equipment and at most two Iron Ingots, and no player-specific progression state controls shared loot. +- Smith equipment trades unlock Copper at Apprentice for 8–12 Emeralds, Iron at Expert for 24–32, and unenchanted plus rarer enchanted Diamond at Master for 48–64. The Wandering Trader may sell its rare enchanted Iron Pickaxe for roughly 48 Emeralds after its enchantment surcharge. - Campfires use three Sticks and three Logs without Coal or Flint, begin unlit, and can be lit by consuming bare Flint or by using Flint and Steel durability. - Campfire cooking fires Clay Balls into Bricks. - Brick Furnace fills the Smoker role, smelts Copper, and is crafted from eight Bricks in a ring. @@ -542,6 +546,7 @@ Copper rate again only from concrete natural-world results. - Iron makes Stone mining practical. - Steel is produced by blasting Iron Ingots; Charcoal is an ordinary valid fuel rather than a required second ingredient. - Steel makes Deepslate practical and thereby opens deep Diamond progression. +- Ancient Debris remains in the Diamond harvest tier. - Copper and Steel receive full tool and armor sets. - Standard tool families follow the same tier ladder from Copper onward. - Diamond equipment has very low durability until enchanted. @@ -550,6 +555,7 @@ Copper rate again only from concrete natural-world results. - Aenderite is the final exotic tier but must have an identity beyond bigger stats. - Keep vanilla Iron and Diamond generation; Copper is the confirmed exception at six vein attempts per chunk with vanilla vein sizes. - Gold is intentionally deferred to a separate design pass. +- Mending is excluded from new random loot and Librarian trades, but remains registered and functional on existing or command/Creative-created items. ## Still Undecided @@ -557,8 +563,7 @@ Copper rate again only from concrete natural-world results. - final tool mining speeds and durability per tier beyond the provisional Flint, Copper, Steel, and unenchanted Diamond values - final armor/combat stats beyond the provisional Steel and unenchanted Diamond values - exact block/tag harvest lists beyond the implemented Flint and Steel-tier opening boundaries -- exact handling of Ancient Debris harvest level - exact role and progression position of Gold - whether Smithing Table remains or Netherite upgrade functionality moves into the Anvil - exact Aenderite crafting/upgrading method and special abilities -- whether any nonstandard tools/weapons follow different material rules after the future combat/tool audit +- whether later nonstandard tools/weapons follow different material rules after the future combat/tool audit diff --git a/src/main/java/cz/xefensor/retold/gametest/RetoldGameTests.java b/src/main/java/cz/xefensor/retold/gametest/RetoldGameTests.java index a6fb819..863839c 100644 --- a/src/main/java/cz/xefensor/retold/gametest/RetoldGameTests.java +++ b/src/main/java/cz/xefensor/retold/gametest/RetoldGameTests.java @@ -50,6 +50,7 @@ import cz.xefensor.retold.event.RetoldSnowballGameTests; import cz.xefensor.retold.event.RetoldVexGameTests; import cz.xefensor.retold.progression.RetoldToolProgressionGameTests; +import cz.xefensor.retold.progression.RetoldProgressionAcquisitionGameTests; import cz.xefensor.retold.registry.RetoldBlocks; import cz.xefensor.retold.stage.RetoldElementType; import cz.xefensor.retold.stage.RetoldRaidProgression; @@ -260,6 +261,7 @@ public static void register(RegisterGameTestsEvent event) { RetoldSnowballGameTests.register(event, environment); RetoldEnchantingGameTests.register(event, environment); RetoldToolProgressionGameTests.register(event, environment); + RetoldProgressionAcquisitionGameTests.register(event, environment); RetoldTerritoryGameTests.register(event, environment); RetoldVillagerCommunalFoodGameTests.register(event); RetoldVillagerGolemConstructionGameTests.register(event); diff --git a/src/main/java/cz/xefensor/retold/progression/RetoldLeafStickLootModifier.java b/src/main/java/cz/xefensor/retold/progression/RetoldLeafStickLootModifier.java index ea14942..5520715 100644 --- a/src/main/java/cz/xefensor/retold/progression/RetoldLeafStickLootModifier.java +++ b/src/main/java/cz/xefensor/retold/progression/RetoldLeafStickLootModifier.java @@ -2,6 +2,7 @@ import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; +import cz.xefensor.retold.registry.RetoldTags; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import net.minecraft.core.registries.Registries; import net.minecraft.tags.BlockTags; @@ -9,6 +10,7 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.item.enchantment.Enchantments; +import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.storage.loot.LootContext; import net.minecraft.world.level.storage.loot.parameters.LootContextParams; @@ -23,6 +25,7 @@ public final class RetoldLeafStickLootModifier extends LootModifier { static final float BASE_CHANCE = 0.20F; static final float FORTUNE_CHANCE_PER_LEVEL = 0.05F; + static final float LIVING_BUSH_CHANCE = 0.10F; public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> codecStart(instance).apply( @@ -46,7 +49,7 @@ protected ObjectArrayList doApply( LootContextParams.BLOCK_STATE ); ItemInstance tool = context.getOptionalParameter(LootContextParams.TOOL); - if (state == null || tool == null || !state.is(BlockTags.LEAVES)) { + if (state == null || tool == null || !canSupplySticks(state)) { return generatedLoot; } @@ -60,14 +63,28 @@ protected ObjectArrayList doApply( return generatedLoot; } + if (state.is(Blocks.DEAD_BUSH)) { + generatedLoot.removeIf(stack -> stack.is(Items.STICK)); + generatedLoot.add(new ItemStack( + Items.STICK, + 2 + context.getRandom().nextInt(3) + )); + return generatedLoot; + } + int fortuneLevel = tool.getEnchantmentLevel( enchantments.getOrThrow(Enchantments.FORTUNE) ); - if (context.getRandom().nextFloat() < chanceForFortune(fortuneLevel)) { + if (state.is(BlockTags.LEAVES) + && context.getRandom().nextFloat() + < chanceForFortune(fortuneLevel)) { generatedLoot.add(new ItemStack( Items.STICK, 1 + context.getRandom().nextInt(2) )); + } else if (state.is(RetoldTags.STICK_DROPPING_LIVING_BUSHES) + && context.getRandom().nextFloat() < LIVING_BUSH_CHANCE) { + generatedLoot.add(new ItemStack(Items.STICK)); } return generatedLoot; @@ -82,6 +99,12 @@ static float chanceForFortune(int fortuneLevel) { ); } + private static boolean canSupplySticks(BlockState state) { + return state.is(BlockTags.LEAVES) + || state.is(Blocks.DEAD_BUSH) + || state.is(RetoldTags.STICK_DROPPING_LIVING_BUSHES); + } + @Override public MapCodec codec() { return RetoldLootModifiers.MORE_LEAF_STICKS.get(); diff --git a/src/main/java/cz/xefensor/retold/progression/RetoldProgressionAcquisitionGameTests.java b/src/main/java/cz/xefensor/retold/progression/RetoldProgressionAcquisitionGameTests.java new file mode 100644 index 0000000..251b5b1 --- /dev/null +++ b/src/main/java/cz/xefensor/retold/progression/RetoldProgressionAcquisitionGameTests.java @@ -0,0 +1,375 @@ +package cz.xefensor.retold.progression; + +import cz.xefensor.retold.registry.RetoldBlocks; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Holder; +import net.minecraft.core.registries.Registries; +import net.minecraft.gametest.framework.BuiltinTestFunctions; +import net.minecraft.gametest.framework.FunctionGameTestInstance; +import net.minecraft.gametest.framework.GameTestHelper; +import net.minecraft.gametest.framework.TestData; +import net.minecraft.gametest.framework.TestEnvironmentDefinition; +import net.minecraft.resources.Identifier; +import net.minecraft.resources.ResourceKey; +import net.minecraft.tags.EnchantmentTags; +import net.minecraft.tags.TagKey; +import net.minecraft.util.Unit; +import net.minecraft.world.entity.EntityTypes; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.enchantment.Enchantments; +import net.minecraft.world.item.trading.MerchantOffer; +import net.minecraft.world.item.trading.VillagerTrade; +import net.minecraft.world.level.storage.loot.LootContext; +import net.minecraft.world.level.storage.loot.LootParams; +import net.minecraft.world.level.storage.loot.LootTable; +import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets; +import net.minecraft.world.level.storage.loot.parameters.LootContextParams; +import net.minecraft.world.phys.Vec3; +import net.neoforged.neoforge.event.RegisterGameTestsEvent; + +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.function.Consumer; + +public final class RetoldProgressionAcquisitionGameTests { + private static final Identifier EMPTY_STRUCTURE = + Identifier.withDefaultNamespace("empty"); + private static final Set COPPER_EQUIPMENT = Set.of( + Items.COPPER_AXE, Items.COPPER_HOE, Items.COPPER_PICKAXE, + Items.COPPER_SHOVEL, Items.COPPER_SWORD, Items.COPPER_SPEAR, + Items.COPPER_HELMET, Items.COPPER_CHESTPLATE, + Items.COPPER_LEGGINGS, Items.COPPER_BOOTS + ); + private static final Set IRON_EQUIPMENT = Set.of( + Items.IRON_AXE, Items.IRON_HOE, Items.IRON_PICKAXE, + Items.IRON_SHOVEL, Items.IRON_SWORD, Items.IRON_SPEAR, + Items.IRON_HELMET, Items.IRON_CHESTPLATE, + Items.IRON_LEGGINGS, Items.IRON_BOOTS + ); + private static final Set DIAMOND_EQUIPMENT = Set.of( + Items.DIAMOND_AXE, Items.DIAMOND_HOE, Items.DIAMOND_PICKAXE, + Items.DIAMOND_SHOVEL, Items.DIAMOND_SWORD, Items.DIAMOND_SPEAR, + Items.DIAMOND_HELMET, Items.DIAMOND_CHESTPLATE, + Items.DIAMOND_LEGGINGS, Items.DIAMOND_BOOTS + ); + private static final Set VILLAGE_CHEST_FORBIDDEN_ITEMS = Set.of( + Items.DIAMOND, Items.DIAMOND_HORSE_ARMOR, Items.OBSIDIAN, + Items.IRON_AXE, Items.IRON_HOE, Items.IRON_PICKAXE, + Items.IRON_SHOVEL, Items.IRON_SWORD, Items.IRON_SPEAR, + Items.IRON_HELMET, Items.IRON_CHESTPLATE, + Items.IRON_LEGGINGS, Items.IRON_BOOTS, Items.IRON_HORSE_ARMOR + ); + + private RetoldProgressionAcquisitionGameTests() { + } + + public static void register( + RegisterGameTestsEvent event, + Holder> environment + ) { + TestData>> testData = + new TestData<>(environment, EMPTY_STRUCTURE, 40, 0, true); + event.registerTest( + retoldId("tool_progression_alternative_acquisition_respects_tiers"), + new InlineGameTest( + testData, + RetoldProgressionAcquisitionGameTests + ::alternativeAcquisitionRespectsTiers + ) + ); + } + + private static void alternativeAcquisitionRespectsTiers( + GameTestHelper helper + ) { + assertBonusChestStartsAtFlint(helper); + assertVillageSmithChestsStopAtCopper(helper); + + for (String profession : List.of( + "toolsmith", + "weaponsmith", + "armorer" + )) { + assertEquipmentTradeTier(helper, profession, 1, Set.of(), 0, 0); + assertEquipmentTradeTier( + helper, profession, 2, COPPER_EQUIPMENT, 8, 12 + ); + assertEquipmentTradeTier(helper, profession, 3, Set.of(), 0, 0); + assertEquipmentTradeTier( + helper, profession, 4, IRON_EQUIPMENT, 24, 32 + ); + assertEquipmentTradeTier( + helper, profession, 5, DIAMOND_EQUIPMENT, 48, 64 + ); + assertMasterEnchantingMix(helper, profession); + } + + assertWanderingTraderIronPrice(helper); + + var enchantments = helper.getLevel() + .registryAccess() + .lookupOrThrow(Registries.ENCHANTMENT); + Holder mending = + enchantments.getOrThrow(Enchantments.MENDING); + helper.assertFalse( + mending.is(EnchantmentTags.TRADEABLE), + "Mending must not be generated by Librarian trades" + ); + helper.assertFalse( + mending.is(EnchantmentTags.ON_RANDOM_LOOT), + "Mending must not be generated in new random loot" + ); + helper.assertTrue( + mending.is(EnchantmentTags.TREASURE), + "Mending must remain registered for commands and existing items" + ); + helper.succeed(); + } + + private static void assertBonusChestStartsAtFlint(GameTestHelper helper) { + for (long seed = 1L; seed <= 32L; seed++) { + List loot = chestLoot( + helper, + "chests/spawn_bonus_chest", + seed + ); + helper.assertValueEqual( + loot.stream() + .filter(stack -> stack.is( + RetoldBlocks.FLINT_MULTI_TOOL.get() + )) + .count(), + 1L, + "Every bonus chest must supply one Flint Multi-tool" + ); + helper.assertFalse( + loot.stream().anyMatch(stack -> stack.is(Items.WOODEN_AXE) + || stack.is(Items.WOODEN_PICKAXE) + || stack.is(Items.STONE_AXE) + || stack.is(Items.STONE_PICKAXE)), + "Bonus chests must not bypass the Flint starting tier" + ); + } + } + + private static void assertVillageSmithChestsStopAtCopper( + GameTestHelper helper + ) { + for (String table : List.of( + "chests/village/village_toolsmith", + "chests/village/village_weaponsmith", + "chests/village/village_armorer" + )) { + for (long seed = 1L; seed <= 128L; seed++) { + List loot = chestLoot(helper, table, seed); + int ironIngots = loot.stream() + .filter(stack -> stack.is(Items.IRON_INGOT)) + .mapToInt(ItemStack::getCount) + .sum(); + helper.assertTrue( + ironIngots <= 2, + "Village smith chests may contain at most two Iron Ingots" + ); + helper.assertFalse( + loot.stream().anyMatch(stack -> + VILLAGE_CHEST_FORBIDDEN_ITEMS.contains( + stack.getItem() + )), + "Safe Village smith chests must stop at Copper equipment" + ); + } + } + } + + private static List chestLoot( + GameTestHelper helper, + String path, + long seed + ) { + var level = helper.getLevel(); + LootParams params = new LootParams.Builder(level) + .withParameter( + LootContextParams.ORIGIN, + Vec3.atCenterOf(helper.absolutePos(BlockPos.ZERO)) + ) + .create(LootContextParamSets.CHEST); + ResourceKey key = ResourceKey.create( + Registries.LOOT_TABLE, + Identifier.withDefaultNamespace(path) + ); + return level.getServer() + .reloadableRegistries() + .getLootTable(key) + .getRandomItems(params, seed); + } + + private static void assertEquipmentTradeTier( + GameTestHelper helper, + String profession, + int level, + Set allowedEquipment, + int minimumPrice, + int maximumPrice + ) { + var trades = helper.getLevel() + .registryAccess() + .lookupOrThrow(Registries.VILLAGER_TRADE); + TagKey tag = TagKey.create( + Registries.VILLAGER_TRADE, + Identifier.withDefaultNamespace( + profession + "/level_" + level + ) + ); + var entries = trades.get(tag).orElseThrow(() -> + helper.assertionException("Missing Villager trade tag " + tag) + ); + LootContext context = villagerTradeContext(helper, 42L); + boolean foundEquipment = false; + + for (Holder entry : entries) { + MerchantOffer offer = entry.value().getOffer(context); + helper.assertTrue( + offer != null && !offer.getResult().isEmpty(), + "Every configured Villager trade must produce an item" + ); + Item result = offer.getResult().getItem(); + if (!isProgressionEquipment(result)) { + continue; + } + + foundEquipment = true; + helper.assertTrue( + allowedEquipment.contains(result), + profession + " level " + level + + " must offer only its assigned equipment tier" + ); + helper.assertTrue( + offer.getBaseCostA().is(Items.EMERALD) + && offer.getBaseCostA().getCount() >= minimumPrice + && offer.getBaseCostA().getCount() <= maximumPrice, + profession + " level " + level + + " equipment price is outside the approved range" + ); + } + + helper.assertValueEqual( + foundEquipment, + !allowedEquipment.isEmpty(), + profession + " level " + level + + " equipment availability must match progression" + ); + } + + private static boolean isProgressionEquipment(Item item) { + return COPPER_EQUIPMENT.contains(item) + || IRON_EQUIPMENT.contains(item) + || DIAMOND_EQUIPMENT.contains(item); + } + + private static LootContext villagerTradeContext( + GameTestHelper helper, + long seed + ) { + var villager = helper.spawn(EntityTypes.VILLAGER, 1, 2, 1); + LootParams params = new LootParams.Builder(helper.getLevel()) + .withParameter(LootContextParams.ORIGIN, villager.position()) + .withParameter(LootContextParams.THIS_ENTITY, villager) + .withParameter( + LootContextParams.ADDITIONAL_COST_COMPONENT_ALLOWED, + Unit.INSTANCE + ) + .create(LootContextParamSets.VILLAGER_TRADE); + return new LootContext.Builder(params) + .withOptionalRandomSeed(seed) + .create(Optional.empty()); + } + + private static void assertMasterEnchantingMix( + GameTestHelper helper, + String profession + ) { + var trades = helper.getLevel() + .registryAccess() + .lookupOrThrow(Registries.VILLAGER_TRADE); + TagKey tag = TagKey.create( + Registries.VILLAGER_TRADE, + Identifier.withDefaultNamespace(profession + "/level_5") + ); + var entries = trades.get(tag).orElseThrow(); + long enchanted = entries.stream() + .flatMap(holder -> holder.unwrapKey().stream()) + .map(ResourceKey::identifier) + .filter(id -> id.getNamespace().equals("retold") + && id.getPath().contains("enchanted_diamond")) + .count(); + long unenchanted = entries.stream() + .flatMap(holder -> holder.unwrapKey().stream()) + .map(ResourceKey::identifier) + .filter(id -> id.getNamespace().equals("retold") + && id.getPath().startsWith("progression/diamond_")) + .count(); + helper.assertTrue( + enchanted > 0 && enchanted < unenchanted, + "Master " + profession + + " pools must make enchanted Diamond rarer" + ); + } + + private static void assertWanderingTraderIronPrice( + GameTestHelper helper + ) { + var trades = helper.getLevel() + .registryAccess() + .lookupOrThrow(Registries.VILLAGER_TRADE); + ResourceKey key = ResourceKey.create( + Registries.VILLAGER_TRADE, + Identifier.withDefaultNamespace( + "wandering_trader/emerald_enchanted_iron_pickaxe" + ) + ); + int totalPrice = 0; + for (long seed = 1L; seed <= 16L; seed++) { + MerchantOffer offer = trades.getOrThrow(key) + .value() + .getOffer(villagerTradeContext(helper, seed)); + helper.assertTrue( + offer != null + && offer.getResult().is(Items.IRON_PICKAXE) + && offer.getResult().isEnchanted() + && offer.getBaseCostA().is(Items.EMERALD) + && offer.getBaseCostA().getCount() >= 40 + && offer.getBaseCostA().getCount() <= 56, + "Wandering Trader Iron Pickaxe must cost about 48 Emeralds" + ); + totalPrice += offer.getBaseCostA().getCount(); + } + helper.assertTrue( + totalPrice / 16 >= 44 && totalPrice / 16 <= 52, + "Wandering Trader Iron Pickaxe must average about 48 Emeralds" + ); + } + + private static Identifier retoldId(String path) { + return Identifier.fromNamespaceAndPath("retold", path); + } + + private static final class InlineGameTest extends FunctionGameTestInstance { + private final Consumer test; + + private InlineGameTest( + TestData>> testData, + Consumer test + ) { + super(BuiltinTestFunctions.ALWAYS_PASS, testData); + this.test = test; + } + + @Override + public void run(GameTestHelper helper) { + test.accept(helper); + } + } +} diff --git a/src/main/java/cz/xefensor/retold/progression/RetoldToolProgressionGameTests.java b/src/main/java/cz/xefensor/retold/progression/RetoldToolProgressionGameTests.java index e907ca5..042a3ce 100644 --- a/src/main/java/cz/xefensor/retold/progression/RetoldToolProgressionGameTests.java +++ b/src/main/java/cz/xefensor/retold/progression/RetoldToolProgressionGameTests.java @@ -93,6 +93,7 @@ public final class RetoldToolProgressionGameTests { ); private static final List STEEL_EQUIPMENT_RECIPE_IDS = List.of( "steel_sword", + "steel_spear", "steel_shovel", "steel_pickaxe", "steel_axe", @@ -103,6 +104,7 @@ public final class RetoldToolProgressionGameTests { "steel_boots" ); private static final int LEAF_LOOT_SAMPLE_COUNT = 512; + private static final int BUSH_LOOT_SAMPLE_COUNT = 128; private RetoldToolProgressionGameTests() { } @@ -402,8 +404,9 @@ private static void campfiresRequireIgnition(GameTestHelper helper) { } private static void leavesSupplySticks(GameTestHelper helper) { - int unenchantedSticks = countOakLeafSticks( + int unenchantedSticks = countBlockSticks( helper, + Blocks.OAK_LEAVES.defaultBlockState(), ItemStack.EMPTY, LEAF_LOOT_SAMPLE_COUNT ); @@ -420,8 +423,9 @@ private static void leavesSupplySticks(GameTestHelper helper) { enchantments.getOrThrow(Enchantments.FORTUNE), 3 ); - int fortuneSticks = countOakLeafSticks( + int fortuneSticks = countBlockSticks( helper, + Blocks.OAK_LEAVES.defaultBlockState(), fortuneTool, LEAF_LOOT_SAMPLE_COUNT ); @@ -431,8 +435,9 @@ private static void leavesSupplySticks(GameTestHelper helper) { ); helper.assertTrue( - countOakLeafSticks( + countBlockSticks( helper, + Blocks.OAK_LEAVES.defaultBlockState(), new ItemStack(Items.SHEARS), LEAF_LOOT_SAMPLE_COUNT ) == 0, @@ -445,8 +450,9 @@ private static void leavesSupplySticks(GameTestHelper helper) { 1 ); helper.assertTrue( - countOakLeafSticks( + countBlockSticks( helper, + Blocks.OAK_LEAVES.defaultBlockState(), silkTouchTool, LEAF_LOOT_SAMPLE_COUNT ) == 0, @@ -461,11 +467,61 @@ private static void leavesSupplySticks(GameTestHelper helper) { "Leaf Stick chances must remain 20% base and 35% at Fortune III" ); + int deadBushSticks = countBlockSticks( + helper, + Blocks.DEAD_BUSH.defaultBlockState(), + ItemStack.EMPTY, + BUSH_LOOT_SAMPLE_COUNT + ); + helper.assertTrue( + deadBushSticks >= BUSH_LOOT_SAMPLE_COUNT * 2 + && deadBushSticks <= BUSH_LOOT_SAMPLE_COUNT * 4, + "Dead Bushes must drop two to four Sticks" + ); + + helper.assertTrue( + Blocks.BUSH.defaultBlockState().is( + RetoldTags.STICK_DROPPING_LIVING_BUSHES + ) + && Blocks.FIREFLY_BUSH.defaultBlockState().is( + RetoldTags.STICK_DROPPING_LIVING_BUSHES + ) + && Blocks.ROSE_BUSH.defaultBlockState().is( + RetoldTags.STICK_DROPPING_LIVING_BUSHES + ) + && Blocks.SWEET_BERRY_BUSH.defaultBlockState().is( + RetoldTags.STICK_DROPPING_LIVING_BUSHES + ), + "Every woody vanilla bush must use the living-bush Stick policy" + ); + int livingBushSticks = countBlockSticks( + helper, + Blocks.BUSH.defaultBlockState(), + ItemStack.EMPTY, + BUSH_LOOT_SAMPLE_COUNT + ); + helper.assertTrue( + livingBushSticks >= 4 && livingBushSticks <= 25, + "Living bushes must occasionally drop one Stick; sampled " + + livingBushSticks + ); + helper.assertValueEqual( + countBlockSticks( + helper, + Blocks.BUSH.defaultBlockState(), + new ItemStack(Items.SHEARS), + BUSH_LOOT_SAMPLE_COUNT + ), + 0, + "Shears must preserve living bushes without extra Sticks" + ); + helper.succeed(); } - private static int countOakLeafSticks( + private static int countBlockSticks( GameTestHelper helper, + BlockState state, ItemStack tool, int samples ) { @@ -477,19 +533,19 @@ private static int countOakLeafSticks( ) .withParameter( LootContextParams.BLOCK_STATE, - Blocks.OAK_LEAVES.defaultBlockState() + state ) .withParameter(LootContextParams.TOOL, tool) .create(LootContextParamSets.BLOCK); LootTable lootTable = level.getServer() .reloadableRegistries() .getLootTable( - Blocks.OAK_LEAVES.getLootTable().orElseThrow() + state.getBlock().getLootTable().orElseThrow() ); int sticks = 0; - for (long seed = 1L; seed <= samples; seed++) { - for (ItemStack stack : lootTable.getRandomItems(params, seed)) { + for (int sample = 0; sample < samples; sample++) { + for (ItemStack stack : lootTable.getRandomItems(params)) { if (stack.is(Items.STICK)) { sticks += stack.getCount(); } @@ -771,6 +827,21 @@ private static void recipesEnforceOpeningLoop(GameTestHelper helper) { .is(RetoldBlocks.FLINT_MULTI_TOOL.get()), "The opening recipe must produce the Flint Multi-tool" ); + assertSpearRecipe( + helper, + recipes, + Items.FLINT, + RetoldBlocks.FLINT_SPEAR.get(), + "Flint" + ); + helper.assertTrue( + RetoldBlocks.FLINT_SPEAR.get().getDefaultInstance() + .is(ItemTags.SPEARS) + && RetoldBlocks.FLINT_SPEAR.get() + .getDefaultInstance() + .getMaxDamage() == 48, + "The Flint Spear must join the Spear family at Flint durability" + ); CraftingInput unfueledCampfireInput = campfireInput(ItemStack.EMPTY); RecipeHolder loadedCampfireRecipe = recipes.byKey( @@ -879,6 +950,21 @@ private static void recipesEnforceOpeningLoop(GameTestHelper helper) { "Steel equipment recipe must load: " + steelRecipeId ); } + assertSpearRecipe( + helper, + recipes, + RetoldBlocks.STEEL_INGOT.get(), + RetoldBlocks.STEEL_SPEAR.get(), + "Steel" + ); + helper.assertTrue( + RetoldBlocks.STEEL_SPEAR.get().getDefaultInstance() + .is(ItemTags.SPEARS) + && RetoldBlocks.STEEL_SPEAR.get() + .getDefaultInstance() + .getMaxDamage() == 750, + "The Steel Spear must join the Spear family at Steel durability" + ); CraftingInput steelPickaxeInput = CraftingInput.of( 3, @@ -916,6 +1002,41 @@ private static void recipesEnforceOpeningLoop(GameTestHelper helper) { helper.succeed(); } + private static void assertSpearRecipe( + GameTestHelper helper, + RecipeManager recipes, + Item point, + Item expectedResult, + String tier + ) { + CraftingInput input = CraftingInput.of( + 3, + 3, + List.of( + ItemStack.EMPTY, + ItemStack.EMPTY, + point.getDefaultInstance(), + ItemStack.EMPTY, + Items.STICK.getDefaultInstance(), + ItemStack.EMPTY, + Items.STICK.getDefaultInstance(), + ItemStack.EMPTY, + ItemStack.EMPTY + ) + ); + RecipeHolder recipe = recipes.getRecipeFor( + RecipeType.CRAFTING, + input, + helper.getLevel() + ).orElseThrow(() -> helper.assertionException( + tier + " must use the standard diagonal Spear recipe" + )); + helper.assertTrue( + recipe.value().assemble(input).is(expectedResult), + tier + " Spear recipe must produce the registered Spear" + ); + } + private static void assertSmokingResult( GameTestHelper helper, RecipeManager recipes, diff --git a/src/main/java/cz/xefensor/retold/registry/RetoldBlocks.java b/src/main/java/cz/xefensor/retold/registry/RetoldBlocks.java index 06499f4..bc198a1 100644 --- a/src/main/java/cz/xefensor/retold/registry/RetoldBlocks.java +++ b/src/main/java/cz/xefensor/retold/registry/RetoldBlocks.java @@ -94,6 +94,22 @@ public final class RetoldBlocks { 0.0F ) ); + public static final DeferredItem FLINT_SPEAR = ITEMS.registerItem( + "flint_spear", + Item::new, + properties -> properties.spear( + FLINT_MULTI_TOOL_MATERIAL, + 0.75F, + 0.82F, + 0.70F, + 4.5F, + 13.0F, + 9.0F, + 5.1F, + 13.75F, + 4.6F + ) + ); public static final DeferredItem STEEL_INGOT = ITEMS.registerSimpleItem( "steel_ingot" ); @@ -106,6 +122,22 @@ public final class RetoldBlocks { -2.4F ) ); + public static final DeferredItem STEEL_SPEAR = ITEMS.registerItem( + "steel_spear", + Item::new, + properties -> properties.spear( + STEEL_TOOL_MATERIAL, + 1.0F, + 1.0F, + 0.55F, + 2.75F, + 10.5F, + 6.625F, + 5.1F, + 10.625F, + 4.6F + ) + ); public static final DeferredItem STEEL_SHOVEL = ITEMS.registerItem( "steel_shovel", properties -> new ShovelItem( diff --git a/src/main/java/cz/xefensor/retold/registry/RetoldCreativeModeTabs.java b/src/main/java/cz/xefensor/retold/registry/RetoldCreativeModeTabs.java index 378141f..5dc908c 100644 --- a/src/main/java/cz/xefensor/retold/registry/RetoldCreativeModeTabs.java +++ b/src/main/java/cz/xefensor/retold/registry/RetoldCreativeModeTabs.java @@ -98,7 +98,8 @@ private static void addToolsAndUtilities(BuildCreativeModeTabContentsEvent event insertAfter( event, Items.FLINT_AND_STEEL, - RetoldBlocks.FLINT_MULTI_TOOL.get() + RetoldBlocks.FLINT_MULTI_TOOL.get(), + RetoldBlocks.FLINT_SPEAR.get() ); insertAfter( event, @@ -114,6 +115,7 @@ private static void addToolsAndUtilities(BuildCreativeModeTabContentsEvent event private static void addCombat(BuildCreativeModeTabContentsEvent event) { insertAfter(event, Items.IRON_SWORD, RetoldBlocks.STEEL_SWORD.get()); + insertAfter(event, Items.IRON_SPEAR, RetoldBlocks.STEEL_SPEAR.get()); insertAfter(event, Items.IRON_AXE, RetoldBlocks.STEEL_AXE.get()); insertAfter(event, Items.IRON_HELMET, RetoldBlocks.STEEL_HELMET.get()); insertAfter( diff --git a/src/main/java/cz/xefensor/retold/registry/RetoldTags.java b/src/main/java/cz/xefensor/retold/registry/RetoldTags.java index 801b003..a22f574 100644 --- a/src/main/java/cz/xefensor/retold/registry/RetoldTags.java +++ b/src/main/java/cz/xefensor/retold/registry/RetoldTags.java @@ -81,6 +81,14 @@ public final class RetoldTags { "steel_tier_blocks" ) ); + public static final TagKey STICK_DROPPING_LIVING_BUSHES = + TagKey.create( + Registries.BLOCK, + Identifier.fromNamespaceAndPath( + Retold.MODID, + "stick_dropping_living_bushes" + ) + ); public static final TagKey WEAK_MOB_BARRIERS = TagKey.create( Registries.BLOCK, Identifier.fromNamespaceAndPath(Retold.MODID, "weak_mob_barriers") diff --git a/src/main/resources/assets/retold/items/flint_spear.json b/src/main/resources/assets/retold/items/flint_spear.json new file mode 100644 index 0000000..b7ff880 --- /dev/null +++ b/src/main/resources/assets/retold/items/flint_spear.json @@ -0,0 +1,25 @@ +{ + "model": { + "type": "minecraft:select", + "cases": [ + { + "model": { + "type": "minecraft:model", + "model": "minecraft:item/stone_spear" + }, + "when": [ + "gui", + "ground", + "fixed", + "on_shelf" + ] + } + ], + "fallback": { + "type": "minecraft:model", + "model": "minecraft:item/stone_spear_in_hand" + }, + "property": "minecraft:display_context" + }, + "swap_animation_scale": 1.95 +} diff --git a/src/main/resources/assets/retold/items/steel_spear.json b/src/main/resources/assets/retold/items/steel_spear.json new file mode 100644 index 0000000..a1e4a8d --- /dev/null +++ b/src/main/resources/assets/retold/items/steel_spear.json @@ -0,0 +1,25 @@ +{ + "model": { + "type": "minecraft:select", + "cases": [ + { + "model": { + "type": "minecraft:model", + "model": "minecraft:item/iron_spear" + }, + "when": [ + "gui", + "ground", + "fixed", + "on_shelf" + ] + } + ], + "fallback": { + "type": "minecraft:model", + "model": "minecraft:item/iron_spear_in_hand" + }, + "property": "minecraft:display_context" + }, + "swap_animation_scale": 1.95 +} diff --git a/src/main/resources/assets/retold/lang/en_us.json b/src/main/resources/assets/retold/lang/en_us.json index 91f41d2..4b1d9f9 100644 --- a/src/main/resources/assets/retold/lang/en_us.json +++ b/src/main/resources/assets/retold/lang/en_us.json @@ -74,8 +74,10 @@ "item.retold.aender_chest_boat": "Aender Chest Boat", "item.retold.aender_eye_spawn_egg": "Aender Eye Spawn Egg", "item.retold.flint_multi_tool": "Flint Multi-tool", + "item.retold.flint_spear": "Flint Spear", "item.retold.steel_ingot": "Steel Ingot", "item.retold.steel_sword": "Steel Sword", + "item.retold.steel_spear": "Steel Spear", "item.retold.steel_shovel": "Steel Shovel", "item.retold.steel_pickaxe": "Steel Pickaxe", "item.retold.steel_axe": "Steel Axe", diff --git a/src/main/resources/data/minecraft/loot_table/chests/spawn_bonus_chest.json b/src/main/resources/data/minecraft/loot_table/chests/spawn_bonus_chest.json new file mode 100644 index 0000000..a24314a --- /dev/null +++ b/src/main/resources/data/minecraft/loot_table/chests/spawn_bonus_chest.json @@ -0,0 +1,205 @@ +{ + "type": "minecraft:chest", + "pools": [ + { + "entries": [ + { + "type": "minecraft:item", + "name": "retold:flint_multi_tool" + } + ], + "rolls": 1.0 + }, + { + "entries": [ + { + "type": "minecraft:item", + "functions": [ + { + "count": { + "type": "minecraft:uniform", + "max": 2.0, + "min": 1.0 + }, + "function": "minecraft:set_count" + } + ], + "name": "minecraft:apple", + "weight": 5 + }, + { + "type": "minecraft:item", + "functions": [ + { + "count": { + "type": "minecraft:uniform", + "max": 2.0, + "min": 1.0 + }, + "function": "minecraft:set_count" + } + ], + "name": "minecraft:bread", + "weight": 3 + }, + { + "type": "minecraft:item", + "functions": [ + { + "count": { + "type": "minecraft:uniform", + "max": 2.0, + "min": 1.0 + }, + "function": "minecraft:set_count" + } + ], + "name": "minecraft:salmon", + "weight": 3 + } + ], + "rolls": 3.0 + }, + { + "entries": [ + { + "type": "minecraft:item", + "functions": [ + { + "count": { + "type": "minecraft:uniform", + "max": 12.0, + "min": 1.0 + }, + "function": "minecraft:set_count" + } + ], + "name": "minecraft:stick", + "weight": 10 + }, + { + "type": "minecraft:item", + "functions": [ + { + "count": { + "type": "minecraft:uniform", + "max": 12.0, + "min": 1.0 + }, + "function": "minecraft:set_count" + } + ], + "name": "minecraft:oak_planks", + "weight": 10 + }, + { + "type": "minecraft:item", + "functions": [ + { + "count": { + "type": "minecraft:uniform", + "max": 3.0, + "min": 1.0 + }, + "function": "minecraft:set_count" + } + ], + "name": "minecraft:oak_log", + "weight": 3 + }, + { + "type": "minecraft:item", + "functions": [ + { + "count": { + "type": "minecraft:uniform", + "max": 3.0, + "min": 1.0 + }, + "function": "minecraft:set_count" + } + ], + "name": "minecraft:spruce_log", + "weight": 3 + }, + { + "type": "minecraft:item", + "functions": [ + { + "count": { + "type": "minecraft:uniform", + "max": 3.0, + "min": 1.0 + }, + "function": "minecraft:set_count" + } + ], + "name": "minecraft:birch_log", + "weight": 3 + }, + { + "type": "minecraft:item", + "functions": [ + { + "count": { + "type": "minecraft:uniform", + "max": 3.0, + "min": 1.0 + }, + "function": "minecraft:set_count" + } + ], + "name": "minecraft:jungle_log", + "weight": 3 + }, + { + "type": "minecraft:item", + "functions": [ + { + "count": { + "type": "minecraft:uniform", + "max": 3.0, + "min": 1.0 + }, + "function": "minecraft:set_count" + } + ], + "name": "minecraft:acacia_log", + "weight": 3 + }, + { + "type": "minecraft:item", + "functions": [ + { + "count": { + "type": "minecraft:uniform", + "max": 3.0, + "min": 1.0 + }, + "function": "minecraft:set_count" + } + ], + "name": "minecraft:dark_oak_log", + "weight": 3 + }, + { + "type": "minecraft:item", + "functions": [ + { + "count": { + "type": "minecraft:uniform", + "max": 3.0, + "min": 1.0 + }, + "function": "minecraft:set_count" + } + ], + "name": "minecraft:mangrove_log", + "weight": 3 + } + ], + "rolls": 4.0 + } + ], + "random_sequence": "minecraft:chests/spawn_bonus_chest" +} diff --git a/src/main/resources/data/minecraft/loot_table/chests/village/village_armorer.json b/src/main/resources/data/minecraft/loot_table/chests/village/village_armorer.json new file mode 100644 index 0000000..1bcd9b8 --- /dev/null +++ b/src/main/resources/data/minecraft/loot_table/chests/village/village_armorer.json @@ -0,0 +1,88 @@ +{ + "type": "minecraft:chest", + "pools": [ + { + "entries": [ + { + "type": "minecraft:item", + "functions": [ + { + "count": { + "type": "minecraft:uniform", + "max": 3.0, + "min": 1.0 + }, + "function": "minecraft:set_count" + } + ], + "name": "minecraft:copper_ingot", + "weight": 4 + }, + { + "type": "minecraft:item", + "functions": [ + { + "count": { + "type": "minecraft:uniform", + "max": 4.0, + "min": 1.0 + }, + "function": "minecraft:set_count" + } + ], + "name": "minecraft:bread", + "weight": 4 + }, + { + "type": "minecraft:item", + "name": "minecraft:copper_helmet" + }, + { + "type": "minecraft:item", + "name": "minecraft:copper_chestplate" + }, + { + "type": "minecraft:item", + "name": "minecraft:copper_leggings" + }, + { + "type": "minecraft:item", + "name": "minecraft:copper_boots" + }, + { + "type": "minecraft:item", + "name": "minecraft:emerald" + } + ], + "rolls": { + "type": "minecraft:uniform", + "max": 5.0, + "min": 1.0 + } + }, + { + "entries": [ + { + "type": "minecraft:item", + "functions": [ + { + "count": { + "type": "minecraft:uniform", + "max": 2.0, + "min": 1.0 + }, + "function": "minecraft:set_count" + } + ], + "name": "minecraft:iron_ingot" + }, + { + "type": "minecraft:empty", + "weight": 3 + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "minecraft:chests/village/village_armorer" +} diff --git a/src/main/resources/data/minecraft/loot_table/chests/village/village_toolsmith.json b/src/main/resources/data/minecraft/loot_table/chests/village/village_toolsmith.json new file mode 100644 index 0000000..e95e345 --- /dev/null +++ b/src/main/resources/data/minecraft/loot_table/chests/village/village_toolsmith.json @@ -0,0 +1,107 @@ +{ + "type": "minecraft:chest", + "pools": [ + { + "entries": [ + { + "type": "minecraft:item", + "functions": [ + { + "count": { + "type": "minecraft:uniform", + "max": 3.0, + "min": 1.0 + }, + "function": "minecraft:set_count" + } + ], + "name": "minecraft:copper_ingot", + "weight": 10 + }, + { + "type": "minecraft:item", + "functions": [ + { + "count": { + "type": "minecraft:uniform", + "max": 3.0, + "min": 1.0 + }, + "function": "minecraft:set_count" + } + ], + "name": "minecraft:bread", + "weight": 15 + }, + { + "type": "minecraft:item", + "name": "minecraft:copper_pickaxe", + "weight": 5 + }, + { + "type": "minecraft:item", + "name": "minecraft:copper_shovel", + "weight": 5 + }, + { + "type": "minecraft:item", + "functions": [ + { + "count": { + "type": "minecraft:uniform", + "max": 3.0, + "min": 1.0 + }, + "function": "minecraft:set_count" + } + ], + "name": "minecraft:coal" + }, + { + "type": "minecraft:item", + "functions": [ + { + "count": { + "type": "minecraft:uniform", + "max": 3.0, + "min": 1.0 + }, + "function": "minecraft:set_count" + } + ], + "name": "minecraft:stick", + "weight": 20 + } + ], + "rolls": { + "type": "minecraft:uniform", + "max": 6.0, + "min": 3.0 + } + }, + { + "entries": [ + { + "type": "minecraft:item", + "functions": [ + { + "count": { + "type": "minecraft:uniform", + "max": 2.0, + "min": 1.0 + }, + "function": "minecraft:set_count" + } + ], + "name": "minecraft:iron_ingot" + }, + { + "type": "minecraft:empty", + "weight": 3 + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "minecraft:chests/village/village_toolsmith" +} diff --git a/src/main/resources/data/minecraft/loot_table/chests/village/village_weaponsmith.json b/src/main/resources/data/minecraft/loot_table/chests/village/village_weaponsmith.json new file mode 100644 index 0000000..1ca8bb8 --- /dev/null +++ b/src/main/resources/data/minecraft/loot_table/chests/village/village_weaponsmith.json @@ -0,0 +1,156 @@ +{ + "type": "minecraft:chest", + "pools": [ + { + "entries": [ + { + "type": "minecraft:item", + "functions": [ + { + "count": { + "type": "minecraft:uniform", + "max": 3.0, + "min": 1.0 + }, + "function": "minecraft:set_count" + } + ], + "name": "minecraft:copper_ingot", + "weight": 10 + }, + { + "type": "minecraft:item", + "functions": [ + { + "count": { + "type": "minecraft:uniform", + "max": 3.0, + "min": 1.0 + }, + "function": "minecraft:set_count" + } + ], + "name": "minecraft:gold_ingot", + "weight": 5 + }, + { + "type": "minecraft:item", + "functions": [ + { + "count": { + "type": "minecraft:uniform", + "max": 3.0, + "min": 1.0 + }, + "function": "minecraft:set_count" + } + ], + "name": "minecraft:bread", + "weight": 15 + }, + { + "type": "minecraft:item", + "functions": [ + { + "count": { + "type": "minecraft:uniform", + "max": 3.0, + "min": 1.0 + }, + "function": "minecraft:set_count" + } + ], + "name": "minecraft:apple", + "weight": 15 + }, + { + "type": "minecraft:item", + "name": "minecraft:copper_pickaxe", + "weight": 5 + }, + { + "type": "minecraft:item", + "name": "minecraft:copper_sword", + "weight": 5 + }, + { + "type": "minecraft:item", + "name": "minecraft:copper_spear", + "weight": 5 + }, + { + "type": "minecraft:item", + "name": "minecraft:copper_helmet", + "weight": 3 + }, + { + "type": "minecraft:item", + "name": "minecraft:copper_chestplate", + "weight": 3 + }, + { + "type": "minecraft:item", + "name": "minecraft:copper_leggings", + "weight": 3 + }, + { + "type": "minecraft:item", + "name": "minecraft:copper_boots", + "weight": 3 + }, + { + "type": "minecraft:item", + "name": "minecraft:saddle", + "weight": 3 + }, + { + "type": "minecraft:item", + "name": "minecraft:copper_horse_armor", + "weight": 2 + } + ], + "rolls": { + "type": "minecraft:uniform", + "max": 7.0, + "min": 3.0 + } + }, + { + "entries": [ + { + "type": "minecraft:item", + "functions": [ + { + "count": { + "type": "minecraft:uniform", + "max": 2.0, + "min": 1.0 + }, + "function": "minecraft:set_count" + } + ], + "name": "minecraft:iron_ingot" + }, + { + "type": "minecraft:empty", + "weight": 3 + } + ], + "rolls": 1.0 + }, + { + "entries": [ + { + "type": "minecraft:item", + "name": "minecraft:bundle" + }, + { + "type": "minecraft:empty", + "weight": 2 + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "minecraft:chests/village/village_weaponsmith" +} diff --git a/src/main/resources/data/minecraft/tags/enchantment/on_random_loot.json b/src/main/resources/data/minecraft/tags/enchantment/on_random_loot.json new file mode 100644 index 0000000..73a0dbe --- /dev/null +++ b/src/main/resources/data/minecraft/tags/enchantment/on_random_loot.json @@ -0,0 +1,9 @@ +{ + "replace": true, + "values": [ + "#minecraft:non_treasure", + "minecraft:binding_curse", + "minecraft:vanishing_curse", + "minecraft:frost_walker" + ] +} diff --git a/src/main/resources/data/minecraft/tags/enchantment/tradeable.json b/src/main/resources/data/minecraft/tags/enchantment/tradeable.json new file mode 100644 index 0000000..73a0dbe --- /dev/null +++ b/src/main/resources/data/minecraft/tags/enchantment/tradeable.json @@ -0,0 +1,9 @@ +{ + "replace": true, + "values": [ + "#minecraft:non_treasure", + "minecraft:binding_curse", + "minecraft:vanishing_curse", + "minecraft:frost_walker" + ] +} diff --git a/src/main/resources/data/minecraft/tags/item/spears.json b/src/main/resources/data/minecraft/tags/item/spears.json new file mode 100644 index 0000000..0350f2b --- /dev/null +++ b/src/main/resources/data/minecraft/tags/item/spears.json @@ -0,0 +1,6 @@ +{ + "values": [ + "retold:flint_spear", + "retold:steel_spear" + ] +} diff --git a/src/main/resources/data/minecraft/tags/villager_trade/armorer/level_1.json b/src/main/resources/data/minecraft/tags/villager_trade/armorer/level_1.json new file mode 100644 index 0000000..27388d8 --- /dev/null +++ b/src/main/resources/data/minecraft/tags/villager_trade/armorer/level_1.json @@ -0,0 +1,6 @@ +{ + "replace": true, + "values": [ + "#minecraft:common_smith/level_1" + ] +} diff --git a/src/main/resources/data/minecraft/tags/villager_trade/armorer/level_2.json b/src/main/resources/data/minecraft/tags/villager_trade/armorer/level_2.json new file mode 100644 index 0000000..f1b8fec --- /dev/null +++ b/src/main/resources/data/minecraft/tags/villager_trade/armorer/level_2.json @@ -0,0 +1,10 @@ +{ + "replace": true, + "values": [ + "#minecraft:common_smith/level_2", + "retold:progression/copper_helmet", + "retold:progression/copper_chestplate", + "retold:progression/copper_leggings", + "retold:progression/copper_boots" + ] +} diff --git a/src/main/resources/data/minecraft/tags/villager_trade/armorer/level_3.json b/src/main/resources/data/minecraft/tags/villager_trade/armorer/level_3.json new file mode 100644 index 0000000..6be3fab --- /dev/null +++ b/src/main/resources/data/minecraft/tags/villager_trade/armorer/level_3.json @@ -0,0 +1,9 @@ +{ + "replace": true, + "values": [ + "#minecraft:common_smith/level_3", + "minecraft:armorer/3/lava_bucket_emerald", + "minecraft:armorer/3/emerald_shield", + "minecraft:armorer/3/diamond_emerald" + ] +} diff --git a/src/main/resources/data/minecraft/tags/villager_trade/armorer/level_4.json b/src/main/resources/data/minecraft/tags/villager_trade/armorer/level_4.json new file mode 100644 index 0000000..781a1d1 --- /dev/null +++ b/src/main/resources/data/minecraft/tags/villager_trade/armorer/level_4.json @@ -0,0 +1,10 @@ +{ + "replace": true, + "values": [ + "#minecraft:common_smith/level_4", + "retold:progression/iron_helmet", + "retold:progression/iron_chestplate", + "retold:progression/iron_leggings", + "retold:progression/iron_boots" + ] +} diff --git a/src/main/resources/data/minecraft/tags/villager_trade/armorer/level_5.json b/src/main/resources/data/minecraft/tags/villager_trade/armorer/level_5.json new file mode 100644 index 0000000..52ef8e8 --- /dev/null +++ b/src/main/resources/data/minecraft/tags/villager_trade/armorer/level_5.json @@ -0,0 +1,12 @@ +{ + "replace": true, + "values": [ + "#minecraft:common_smith/level_5", + "retold:progression/diamond_helmet", + "retold:progression/diamond_chestplate", + "retold:progression/diamond_leggings", + "retold:progression/diamond_boots", + "retold:progression/enchanted_diamond_chestplate", + "retold:progression/enchanted_diamond_boots" + ] +} diff --git a/src/main/resources/data/minecraft/tags/villager_trade/toolsmith/level_1.json b/src/main/resources/data/minecraft/tags/villager_trade/toolsmith/level_1.json new file mode 100644 index 0000000..27388d8 --- /dev/null +++ b/src/main/resources/data/minecraft/tags/villager_trade/toolsmith/level_1.json @@ -0,0 +1,6 @@ +{ + "replace": true, + "values": [ + "#minecraft:common_smith/level_1" + ] +} diff --git a/src/main/resources/data/minecraft/tags/villager_trade/toolsmith/level_2.json b/src/main/resources/data/minecraft/tags/villager_trade/toolsmith/level_2.json new file mode 100644 index 0000000..95e3a04 --- /dev/null +++ b/src/main/resources/data/minecraft/tags/villager_trade/toolsmith/level_2.json @@ -0,0 +1,10 @@ +{ + "replace": true, + "values": [ + "#minecraft:common_smith/level_2", + "retold:progression/copper_axe", + "retold:progression/copper_hoe", + "retold:progression/copper_pickaxe", + "retold:progression/copper_shovel" + ] +} diff --git a/src/main/resources/data/minecraft/tags/villager_trade/toolsmith/level_3.json b/src/main/resources/data/minecraft/tags/villager_trade/toolsmith/level_3.json new file mode 100644 index 0000000..8b0cd14 --- /dev/null +++ b/src/main/resources/data/minecraft/tags/villager_trade/toolsmith/level_3.json @@ -0,0 +1,7 @@ +{ + "replace": true, + "values": [ + "#minecraft:common_smith/level_3", + "minecraft:toolsmith/3/flint_emerald" + ] +} diff --git a/src/main/resources/data/minecraft/tags/villager_trade/toolsmith/level_4.json b/src/main/resources/data/minecraft/tags/villager_trade/toolsmith/level_4.json new file mode 100644 index 0000000..a436707 --- /dev/null +++ b/src/main/resources/data/minecraft/tags/villager_trade/toolsmith/level_4.json @@ -0,0 +1,11 @@ +{ + "replace": true, + "values": [ + "#minecraft:common_smith/level_4", + "retold:progression/iron_axe", + "retold:progression/iron_hoe", + "retold:progression/iron_pickaxe", + "retold:progression/iron_shovel", + "minecraft:toolsmith/4/diamond_emerald" + ] +} diff --git a/src/main/resources/data/minecraft/tags/villager_trade/toolsmith/level_5.json b/src/main/resources/data/minecraft/tags/villager_trade/toolsmith/level_5.json new file mode 100644 index 0000000..bf2e188 --- /dev/null +++ b/src/main/resources/data/minecraft/tags/villager_trade/toolsmith/level_5.json @@ -0,0 +1,12 @@ +{ + "replace": true, + "values": [ + "#minecraft:common_smith/level_5", + "retold:progression/diamond_axe", + "retold:progression/diamond_hoe", + "retold:progression/diamond_pickaxe", + "retold:progression/diamond_shovel", + "retold:progression/enchanted_diamond_axe", + "retold:progression/enchanted_diamond_pickaxe" + ] +} diff --git a/src/main/resources/data/minecraft/tags/villager_trade/weaponsmith/level_1.json b/src/main/resources/data/minecraft/tags/villager_trade/weaponsmith/level_1.json new file mode 100644 index 0000000..27388d8 --- /dev/null +++ b/src/main/resources/data/minecraft/tags/villager_trade/weaponsmith/level_1.json @@ -0,0 +1,6 @@ +{ + "replace": true, + "values": [ + "#minecraft:common_smith/level_1" + ] +} diff --git a/src/main/resources/data/minecraft/tags/villager_trade/weaponsmith/level_2.json b/src/main/resources/data/minecraft/tags/villager_trade/weaponsmith/level_2.json new file mode 100644 index 0000000..dab5696 --- /dev/null +++ b/src/main/resources/data/minecraft/tags/villager_trade/weaponsmith/level_2.json @@ -0,0 +1,9 @@ +{ + "replace": true, + "values": [ + "#minecraft:common_smith/level_2", + "retold:progression/copper_axe", + "retold:progression/copper_sword", + "retold:progression/copper_spear" + ] +} diff --git a/src/main/resources/data/minecraft/tags/villager_trade/weaponsmith/level_3.json b/src/main/resources/data/minecraft/tags/villager_trade/weaponsmith/level_3.json new file mode 100644 index 0000000..62c552f --- /dev/null +++ b/src/main/resources/data/minecraft/tags/villager_trade/weaponsmith/level_3.json @@ -0,0 +1,7 @@ +{ + "replace": true, + "values": [ + "#minecraft:common_smith/level_3", + "minecraft:weaponsmith/3/flint_emerald" + ] +} diff --git a/src/main/resources/data/minecraft/tags/villager_trade/weaponsmith/level_4.json b/src/main/resources/data/minecraft/tags/villager_trade/weaponsmith/level_4.json new file mode 100644 index 0000000..07aaace --- /dev/null +++ b/src/main/resources/data/minecraft/tags/villager_trade/weaponsmith/level_4.json @@ -0,0 +1,10 @@ +{ + "replace": true, + "values": [ + "#minecraft:common_smith/level_4", + "retold:progression/iron_axe", + "retold:progression/iron_sword", + "retold:progression/iron_spear", + "minecraft:weaponsmith/4/diamond_emerald" + ] +} diff --git a/src/main/resources/data/minecraft/tags/villager_trade/weaponsmith/level_5.json b/src/main/resources/data/minecraft/tags/villager_trade/weaponsmith/level_5.json new file mode 100644 index 0000000..0e80ec7 --- /dev/null +++ b/src/main/resources/data/minecraft/tags/villager_trade/weaponsmith/level_5.json @@ -0,0 +1,11 @@ +{ + "replace": true, + "values": [ + "#minecraft:common_smith/level_5", + "retold:progression/diamond_axe", + "retold:progression/diamond_sword", + "retold:progression/diamond_spear", + "retold:progression/enchanted_diamond_sword", + "retold:progression/enchanted_diamond_spear" + ] +} diff --git a/src/main/resources/data/minecraft/villager_trade/wandering_trader/emerald_enchanted_iron_pickaxe.json b/src/main/resources/data/minecraft/villager_trade/wandering_trader/emerald_enchanted_iron_pickaxe.json new file mode 100644 index 0000000..19ff0a6 --- /dev/null +++ b/src/main/resources/data/minecraft/villager_trade/wandering_trader/emerald_enchanted_iron_pickaxe.json @@ -0,0 +1,37 @@ +{ + "given_item_modifiers": [ + { + "function": "minecraft:enchant_with_levels", + "include_additional_cost_component": true, + "levels": { + "type": "minecraft:uniform", + "max": 19, + "min": 5 + }, + "options": "#minecraft:on_traded_equipment" + }, + { + "function": "minecraft:filtered", + "item_filter": { + "items": "minecraft:iron_pickaxe", + "predicates": { + "minecraft:enchantments": [ + {} + ] + } + }, + "on_fail": { + "function": "minecraft:discard" + } + } + ], + "gives": { + "id": "minecraft:iron_pickaxe" + }, + "max_uses": 1, + "reputation_discount": 0.2, + "wants": { + "count": 36, + "id": "minecraft:emerald" + } +} diff --git a/src/main/resources/data/retold/recipe/flint_spear.json b/src/main/resources/data/retold/recipe/flint_spear.json new file mode 100644 index 0000000..13c0c85 --- /dev/null +++ b/src/main/resources/data/retold/recipe/flint_spear.json @@ -0,0 +1,16 @@ +{ + "type": "minecraft:crafting_shaped", + "category": "equipment", + "key": { + "#": "minecraft:stick", + "X": "minecraft:flint" + }, + "pattern": [ + " X", + " # ", + "# " + ], + "result": { + "id": "retold:flint_spear" + } +} diff --git a/src/main/resources/data/retold/recipe/steel_spear.json b/src/main/resources/data/retold/recipe/steel_spear.json new file mode 100644 index 0000000..bee4488 --- /dev/null +++ b/src/main/resources/data/retold/recipe/steel_spear.json @@ -0,0 +1,16 @@ +{ + "type": "minecraft:crafting_shaped", + "category": "equipment", + "key": { + "#": "minecraft:stick", + "X": "#c:ingots/steel" + }, + "pattern": [ + " X", + " # ", + "# " + ], + "result": { + "id": "retold:steel_spear" + } +} diff --git a/src/main/resources/data/retold/tags/block/stick_dropping_living_bushes.json b/src/main/resources/data/retold/tags/block/stick_dropping_living_bushes.json new file mode 100644 index 0000000..9c154f2 --- /dev/null +++ b/src/main/resources/data/retold/tags/block/stick_dropping_living_bushes.json @@ -0,0 +1,8 @@ +{ + "values": [ + "minecraft:bush", + "minecraft:firefly_bush", + "minecraft:rose_bush", + "minecraft:sweet_berry_bush" + ] +} diff --git a/src/main/resources/data/retold/villager_teaching/weaponsmith.json b/src/main/resources/data/retold/villager_teaching/weaponsmith.json index 6b0b09c..d0b554b 100644 --- a/src/main/resources/data/retold/villager_teaching/weaponsmith.json +++ b/src/main/resources/data/retold/villager_teaching/weaponsmith.json @@ -3,9 +3,16 @@ "default_emerald_cost": 4, "default_villager_xp_reward": 2, "recipes": [ + { + "id": "retold:flint_spear", + "emerald_cost": 3 + }, { "id": "minecraft:copper_sword" }, + { + "id": "minecraft:copper_spear" + }, { "id": "minecraft:copper_axe" }, @@ -13,19 +20,36 @@ "id": "minecraft:iron_sword", "emerald_cost": 5 }, + { + "id": "minecraft:iron_spear", + "emerald_cost": 5 + }, { "id": "retold:steel_sword", "emerald_cost": 8 }, + { + "id": "retold:steel_spear", + "emerald_cost": 8 + }, { "id": "minecraft:golden_sword", "emerald_cost": 5 }, + { + "id": "minecraft:golden_spear", + "emerald_cost": 5 + }, { "id": "minecraft:diamond_sword", "emerald_cost": 14, "villager_xp_reward": 5 }, + { + "id": "minecraft:diamond_spear", + "emerald_cost": 14, + "villager_xp_reward": 5 + }, { "id": "minecraft:iron_axe", "emerald_cost": 5 diff --git a/src/main/resources/data/retold/villager_trade/progression/copper_axe.json b/src/main/resources/data/retold/villager_trade/progression/copper_axe.json new file mode 100644 index 0000000..10f3330 --- /dev/null +++ b/src/main/resources/data/retold/villager_trade/progression/copper_axe.json @@ -0,0 +1,12 @@ +{ + "gives": { + "id": "minecraft:copper_axe" + }, + "max_uses": 6, + "reputation_discount": 0.2, + "wants": { + "count": 10, + "id": "minecraft:emerald" + }, + "xp": 5 +} diff --git a/src/main/resources/data/retold/villager_trade/progression/copper_boots.json b/src/main/resources/data/retold/villager_trade/progression/copper_boots.json new file mode 100644 index 0000000..fdbc141 --- /dev/null +++ b/src/main/resources/data/retold/villager_trade/progression/copper_boots.json @@ -0,0 +1,12 @@ +{ + "gives": { + "id": "minecraft:copper_boots" + }, + "max_uses": 6, + "reputation_discount": 0.2, + "wants": { + "count": 8, + "id": "minecraft:emerald" + }, + "xp": 5 +} diff --git a/src/main/resources/data/retold/villager_trade/progression/copper_chestplate.json b/src/main/resources/data/retold/villager_trade/progression/copper_chestplate.json new file mode 100644 index 0000000..f9281d8 --- /dev/null +++ b/src/main/resources/data/retold/villager_trade/progression/copper_chestplate.json @@ -0,0 +1,12 @@ +{ + "gives": { + "id": "minecraft:copper_chestplate" + }, + "max_uses": 6, + "reputation_discount": 0.2, + "wants": { + "count": 12, + "id": "minecraft:emerald" + }, + "xp": 5 +} diff --git a/src/main/resources/data/retold/villager_trade/progression/copper_helmet.json b/src/main/resources/data/retold/villager_trade/progression/copper_helmet.json new file mode 100644 index 0000000..fb2417e --- /dev/null +++ b/src/main/resources/data/retold/villager_trade/progression/copper_helmet.json @@ -0,0 +1,12 @@ +{ + "gives": { + "id": "minecraft:copper_helmet" + }, + "max_uses": 6, + "reputation_discount": 0.2, + "wants": { + "count": 9, + "id": "minecraft:emerald" + }, + "xp": 5 +} diff --git a/src/main/resources/data/retold/villager_trade/progression/copper_hoe.json b/src/main/resources/data/retold/villager_trade/progression/copper_hoe.json new file mode 100644 index 0000000..ab256c1 --- /dev/null +++ b/src/main/resources/data/retold/villager_trade/progression/copper_hoe.json @@ -0,0 +1,12 @@ +{ + "gives": { + "id": "minecraft:copper_hoe" + }, + "max_uses": 6, + "reputation_discount": 0.2, + "wants": { + "count": 8, + "id": "minecraft:emerald" + }, + "xp": 5 +} diff --git a/src/main/resources/data/retold/villager_trade/progression/copper_leggings.json b/src/main/resources/data/retold/villager_trade/progression/copper_leggings.json new file mode 100644 index 0000000..2b504ed --- /dev/null +++ b/src/main/resources/data/retold/villager_trade/progression/copper_leggings.json @@ -0,0 +1,12 @@ +{ + "gives": { + "id": "minecraft:copper_leggings" + }, + "max_uses": 6, + "reputation_discount": 0.2, + "wants": { + "count": 11, + "id": "minecraft:emerald" + }, + "xp": 5 +} diff --git a/src/main/resources/data/retold/villager_trade/progression/copper_pickaxe.json b/src/main/resources/data/retold/villager_trade/progression/copper_pickaxe.json new file mode 100644 index 0000000..f34a8ce --- /dev/null +++ b/src/main/resources/data/retold/villager_trade/progression/copper_pickaxe.json @@ -0,0 +1,12 @@ +{ + "gives": { + "id": "minecraft:copper_pickaxe" + }, + "max_uses": 6, + "reputation_discount": 0.2, + "wants": { + "count": 12, + "id": "minecraft:emerald" + }, + "xp": 5 +} diff --git a/src/main/resources/data/retold/villager_trade/progression/copper_shovel.json b/src/main/resources/data/retold/villager_trade/progression/copper_shovel.json new file mode 100644 index 0000000..aa9a01e --- /dev/null +++ b/src/main/resources/data/retold/villager_trade/progression/copper_shovel.json @@ -0,0 +1,12 @@ +{ + "gives": { + "id": "minecraft:copper_shovel" + }, + "max_uses": 6, + "reputation_discount": 0.2, + "wants": { + "count": 8, + "id": "minecraft:emerald" + }, + "xp": 5 +} diff --git a/src/main/resources/data/retold/villager_trade/progression/copper_spear.json b/src/main/resources/data/retold/villager_trade/progression/copper_spear.json new file mode 100644 index 0000000..4755548 --- /dev/null +++ b/src/main/resources/data/retold/villager_trade/progression/copper_spear.json @@ -0,0 +1,12 @@ +{ + "gives": { + "id": "minecraft:copper_spear" + }, + "max_uses": 6, + "reputation_discount": 0.2, + "wants": { + "count": 12, + "id": "minecraft:emerald" + }, + "xp": 5 +} diff --git a/src/main/resources/data/retold/villager_trade/progression/copper_sword.json b/src/main/resources/data/retold/villager_trade/progression/copper_sword.json new file mode 100644 index 0000000..319b9f6 --- /dev/null +++ b/src/main/resources/data/retold/villager_trade/progression/copper_sword.json @@ -0,0 +1,12 @@ +{ + "gives": { + "id": "minecraft:copper_sword" + }, + "max_uses": 6, + "reputation_discount": 0.2, + "wants": { + "count": 10, + "id": "minecraft:emerald" + }, + "xp": 5 +} diff --git a/src/main/resources/data/retold/villager_trade/progression/diamond_axe.json b/src/main/resources/data/retold/villager_trade/progression/diamond_axe.json new file mode 100644 index 0000000..29f2ec2 --- /dev/null +++ b/src/main/resources/data/retold/villager_trade/progression/diamond_axe.json @@ -0,0 +1,12 @@ +{ + "gives": { + "id": "minecraft:diamond_axe" + }, + "max_uses": 1, + "reputation_discount": 0.2, + "wants": { + "count": 60, + "id": "minecraft:emerald" + }, + "xp": 30 +} diff --git a/src/main/resources/data/retold/villager_trade/progression/diamond_boots.json b/src/main/resources/data/retold/villager_trade/progression/diamond_boots.json new file mode 100644 index 0000000..54f1c01 --- /dev/null +++ b/src/main/resources/data/retold/villager_trade/progression/diamond_boots.json @@ -0,0 +1,12 @@ +{ + "gives": { + "id": "minecraft:diamond_boots" + }, + "max_uses": 1, + "reputation_discount": 0.2, + "wants": { + "count": 48, + "id": "minecraft:emerald" + }, + "xp": 30 +} diff --git a/src/main/resources/data/retold/villager_trade/progression/diamond_chestplate.json b/src/main/resources/data/retold/villager_trade/progression/diamond_chestplate.json new file mode 100644 index 0000000..980b129 --- /dev/null +++ b/src/main/resources/data/retold/villager_trade/progression/diamond_chestplate.json @@ -0,0 +1,12 @@ +{ + "gives": { + "id": "minecraft:diamond_chestplate" + }, + "max_uses": 1, + "reputation_discount": 0.2, + "wants": { + "count": 64, + "id": "minecraft:emerald" + }, + "xp": 30 +} diff --git a/src/main/resources/data/retold/villager_trade/progression/diamond_helmet.json b/src/main/resources/data/retold/villager_trade/progression/diamond_helmet.json new file mode 100644 index 0000000..4e911a2 --- /dev/null +++ b/src/main/resources/data/retold/villager_trade/progression/diamond_helmet.json @@ -0,0 +1,12 @@ +{ + "gives": { + "id": "minecraft:diamond_helmet" + }, + "max_uses": 1, + "reputation_discount": 0.2, + "wants": { + "count": 52, + "id": "minecraft:emerald" + }, + "xp": 30 +} diff --git a/src/main/resources/data/retold/villager_trade/progression/diamond_hoe.json b/src/main/resources/data/retold/villager_trade/progression/diamond_hoe.json new file mode 100644 index 0000000..30a39c4 --- /dev/null +++ b/src/main/resources/data/retold/villager_trade/progression/diamond_hoe.json @@ -0,0 +1,12 @@ +{ + "gives": { + "id": "minecraft:diamond_hoe" + }, + "max_uses": 1, + "reputation_discount": 0.2, + "wants": { + "count": 48, + "id": "minecraft:emerald" + }, + "xp": 30 +} diff --git a/src/main/resources/data/retold/villager_trade/progression/diamond_leggings.json b/src/main/resources/data/retold/villager_trade/progression/diamond_leggings.json new file mode 100644 index 0000000..c2f292c --- /dev/null +++ b/src/main/resources/data/retold/villager_trade/progression/diamond_leggings.json @@ -0,0 +1,12 @@ +{ + "gives": { + "id": "minecraft:diamond_leggings" + }, + "max_uses": 1, + "reputation_discount": 0.2, + "wants": { + "count": 60, + "id": "minecraft:emerald" + }, + "xp": 30 +} diff --git a/src/main/resources/data/retold/villager_trade/progression/diamond_pickaxe.json b/src/main/resources/data/retold/villager_trade/progression/diamond_pickaxe.json new file mode 100644 index 0000000..c00acfe --- /dev/null +++ b/src/main/resources/data/retold/villager_trade/progression/diamond_pickaxe.json @@ -0,0 +1,12 @@ +{ + "gives": { + "id": "minecraft:diamond_pickaxe" + }, + "max_uses": 1, + "reputation_discount": 0.2, + "wants": { + "count": 64, + "id": "minecraft:emerald" + }, + "xp": 30 +} diff --git a/src/main/resources/data/retold/villager_trade/progression/diamond_shovel.json b/src/main/resources/data/retold/villager_trade/progression/diamond_shovel.json new file mode 100644 index 0000000..689ae98 --- /dev/null +++ b/src/main/resources/data/retold/villager_trade/progression/diamond_shovel.json @@ -0,0 +1,12 @@ +{ + "gives": { + "id": "minecraft:diamond_shovel" + }, + "max_uses": 1, + "reputation_discount": 0.2, + "wants": { + "count": 48, + "id": "minecraft:emerald" + }, + "xp": 30 +} diff --git a/src/main/resources/data/retold/villager_trade/progression/diamond_spear.json b/src/main/resources/data/retold/villager_trade/progression/diamond_spear.json new file mode 100644 index 0000000..4a9b65c --- /dev/null +++ b/src/main/resources/data/retold/villager_trade/progression/diamond_spear.json @@ -0,0 +1,12 @@ +{ + "gives": { + "id": "minecraft:diamond_spear" + }, + "max_uses": 1, + "reputation_discount": 0.2, + "wants": { + "count": 60, + "id": "minecraft:emerald" + }, + "xp": 30 +} diff --git a/src/main/resources/data/retold/villager_trade/progression/diamond_sword.json b/src/main/resources/data/retold/villager_trade/progression/diamond_sword.json new file mode 100644 index 0000000..d0bcc68 --- /dev/null +++ b/src/main/resources/data/retold/villager_trade/progression/diamond_sword.json @@ -0,0 +1,12 @@ +{ + "gives": { + "id": "minecraft:diamond_sword" + }, + "max_uses": 1, + "reputation_discount": 0.2, + "wants": { + "count": 56, + "id": "minecraft:emerald" + }, + "xp": 30 +} diff --git a/src/main/resources/data/retold/villager_trade/progression/enchanted_diamond_axe.json b/src/main/resources/data/retold/villager_trade/progression/enchanted_diamond_axe.json new file mode 100644 index 0000000..d78d426 --- /dev/null +++ b/src/main/resources/data/retold/villager_trade/progression/enchanted_diamond_axe.json @@ -0,0 +1,38 @@ +{ + "given_item_modifiers": [ + { + "function": "minecraft:enchant_with_levels", + "include_additional_cost_component": true, + "levels": { + "type": "minecraft:uniform", + "max": 19, + "min": 5 + }, + "options": "#minecraft:on_traded_equipment" + }, + { + "function": "minecraft:filtered", + "item_filter": { + "items": "minecraft:diamond_axe", + "predicates": { + "minecraft:enchantments": [ + {} + ] + } + }, + "on_fail": { + "function": "minecraft:discard" + } + } + ], + "gives": { + "id": "minecraft:diamond_axe" + }, + "max_uses": 1, + "reputation_discount": 0.2, + "wants": { + "count": 64, + "id": "minecraft:emerald" + }, + "xp": 30 +} diff --git a/src/main/resources/data/retold/villager_trade/progression/enchanted_diamond_boots.json b/src/main/resources/data/retold/villager_trade/progression/enchanted_diamond_boots.json new file mode 100644 index 0000000..ac66cb7 --- /dev/null +++ b/src/main/resources/data/retold/villager_trade/progression/enchanted_diamond_boots.json @@ -0,0 +1,38 @@ +{ + "given_item_modifiers": [ + { + "function": "minecraft:enchant_with_levels", + "include_additional_cost_component": true, + "levels": { + "type": "minecraft:uniform", + "max": 19, + "min": 5 + }, + "options": "#minecraft:on_traded_equipment" + }, + { + "function": "minecraft:filtered", + "item_filter": { + "items": "minecraft:diamond_boots", + "predicates": { + "minecraft:enchantments": [ + {} + ] + } + }, + "on_fail": { + "function": "minecraft:discard" + } + } + ], + "gives": { + "id": "minecraft:diamond_boots" + }, + "max_uses": 1, + "reputation_discount": 0.2, + "wants": { + "count": 64, + "id": "minecraft:emerald" + }, + "xp": 30 +} diff --git a/src/main/resources/data/retold/villager_trade/progression/enchanted_diamond_chestplate.json b/src/main/resources/data/retold/villager_trade/progression/enchanted_diamond_chestplate.json new file mode 100644 index 0000000..e1ae35f --- /dev/null +++ b/src/main/resources/data/retold/villager_trade/progression/enchanted_diamond_chestplate.json @@ -0,0 +1,38 @@ +{ + "given_item_modifiers": [ + { + "function": "minecraft:enchant_with_levels", + "include_additional_cost_component": true, + "levels": { + "type": "minecraft:uniform", + "max": 19, + "min": 5 + }, + "options": "#minecraft:on_traded_equipment" + }, + { + "function": "minecraft:filtered", + "item_filter": { + "items": "minecraft:diamond_chestplate", + "predicates": { + "minecraft:enchantments": [ + {} + ] + } + }, + "on_fail": { + "function": "minecraft:discard" + } + } + ], + "gives": { + "id": "minecraft:diamond_chestplate" + }, + "max_uses": 1, + "reputation_discount": 0.2, + "wants": { + "count": 64, + "id": "minecraft:emerald" + }, + "xp": 30 +} diff --git a/src/main/resources/data/retold/villager_trade/progression/enchanted_diamond_pickaxe.json b/src/main/resources/data/retold/villager_trade/progression/enchanted_diamond_pickaxe.json new file mode 100644 index 0000000..771280a --- /dev/null +++ b/src/main/resources/data/retold/villager_trade/progression/enchanted_diamond_pickaxe.json @@ -0,0 +1,38 @@ +{ + "given_item_modifiers": [ + { + "function": "minecraft:enchant_with_levels", + "include_additional_cost_component": true, + "levels": { + "type": "minecraft:uniform", + "max": 19, + "min": 5 + }, + "options": "#minecraft:on_traded_equipment" + }, + { + "function": "minecraft:filtered", + "item_filter": { + "items": "minecraft:diamond_pickaxe", + "predicates": { + "minecraft:enchantments": [ + {} + ] + } + }, + "on_fail": { + "function": "minecraft:discard" + } + } + ], + "gives": { + "id": "minecraft:diamond_pickaxe" + }, + "max_uses": 1, + "reputation_discount": 0.2, + "wants": { + "count": 64, + "id": "minecraft:emerald" + }, + "xp": 30 +} diff --git a/src/main/resources/data/retold/villager_trade/progression/enchanted_diamond_spear.json b/src/main/resources/data/retold/villager_trade/progression/enchanted_diamond_spear.json new file mode 100644 index 0000000..28b08d5 --- /dev/null +++ b/src/main/resources/data/retold/villager_trade/progression/enchanted_diamond_spear.json @@ -0,0 +1,38 @@ +{ + "given_item_modifiers": [ + { + "function": "minecraft:enchant_with_levels", + "include_additional_cost_component": true, + "levels": { + "type": "minecraft:uniform", + "max": 19, + "min": 5 + }, + "options": "#minecraft:on_traded_equipment" + }, + { + "function": "minecraft:filtered", + "item_filter": { + "items": "minecraft:diamond_spear", + "predicates": { + "minecraft:enchantments": [ + {} + ] + } + }, + "on_fail": { + "function": "minecraft:discard" + } + } + ], + "gives": { + "id": "minecraft:diamond_spear" + }, + "max_uses": 1, + "reputation_discount": 0.2, + "wants": { + "count": 64, + "id": "minecraft:emerald" + }, + "xp": 30 +} diff --git a/src/main/resources/data/retold/villager_trade/progression/enchanted_diamond_sword.json b/src/main/resources/data/retold/villager_trade/progression/enchanted_diamond_sword.json new file mode 100644 index 0000000..32b264d --- /dev/null +++ b/src/main/resources/data/retold/villager_trade/progression/enchanted_diamond_sword.json @@ -0,0 +1,38 @@ +{ + "given_item_modifiers": [ + { + "function": "minecraft:enchant_with_levels", + "include_additional_cost_component": true, + "levels": { + "type": "minecraft:uniform", + "max": 19, + "min": 5 + }, + "options": "#minecraft:on_traded_equipment" + }, + { + "function": "minecraft:filtered", + "item_filter": { + "items": "minecraft:diamond_sword", + "predicates": { + "minecraft:enchantments": [ + {} + ] + } + }, + "on_fail": { + "function": "minecraft:discard" + } + } + ], + "gives": { + "id": "minecraft:diamond_sword" + }, + "max_uses": 1, + "reputation_discount": 0.2, + "wants": { + "count": 64, + "id": "minecraft:emerald" + }, + "xp": 30 +} diff --git a/src/main/resources/data/retold/villager_trade/progression/iron_axe.json b/src/main/resources/data/retold/villager_trade/progression/iron_axe.json new file mode 100644 index 0000000..66d2ea4 --- /dev/null +++ b/src/main/resources/data/retold/villager_trade/progression/iron_axe.json @@ -0,0 +1,12 @@ +{ + "gives": { + "id": "minecraft:iron_axe" + }, + "max_uses": 3, + "reputation_discount": 0.2, + "wants": { + "count": 30, + "id": "minecraft:emerald" + }, + "xp": 15 +} diff --git a/src/main/resources/data/retold/villager_trade/progression/iron_boots.json b/src/main/resources/data/retold/villager_trade/progression/iron_boots.json new file mode 100644 index 0000000..3023d63 --- /dev/null +++ b/src/main/resources/data/retold/villager_trade/progression/iron_boots.json @@ -0,0 +1,12 @@ +{ + "gives": { + "id": "minecraft:iron_boots" + }, + "max_uses": 3, + "reputation_discount": 0.2, + "wants": { + "count": 24, + "id": "minecraft:emerald" + }, + "xp": 15 +} diff --git a/src/main/resources/data/retold/villager_trade/progression/iron_chestplate.json b/src/main/resources/data/retold/villager_trade/progression/iron_chestplate.json new file mode 100644 index 0000000..ec3d1dd --- /dev/null +++ b/src/main/resources/data/retold/villager_trade/progression/iron_chestplate.json @@ -0,0 +1,12 @@ +{ + "gives": { + "id": "minecraft:iron_chestplate" + }, + "max_uses": 3, + "reputation_discount": 0.2, + "wants": { + "count": 32, + "id": "minecraft:emerald" + }, + "xp": 15 +} diff --git a/src/main/resources/data/retold/villager_trade/progression/iron_helmet.json b/src/main/resources/data/retold/villager_trade/progression/iron_helmet.json new file mode 100644 index 0000000..92fd8d9 --- /dev/null +++ b/src/main/resources/data/retold/villager_trade/progression/iron_helmet.json @@ -0,0 +1,12 @@ +{ + "gives": { + "id": "minecraft:iron_helmet" + }, + "max_uses": 3, + "reputation_discount": 0.2, + "wants": { + "count": 26, + "id": "minecraft:emerald" + }, + "xp": 15 +} diff --git a/src/main/resources/data/retold/villager_trade/progression/iron_hoe.json b/src/main/resources/data/retold/villager_trade/progression/iron_hoe.json new file mode 100644 index 0000000..8a22c3b --- /dev/null +++ b/src/main/resources/data/retold/villager_trade/progression/iron_hoe.json @@ -0,0 +1,12 @@ +{ + "gives": { + "id": "minecraft:iron_hoe" + }, + "max_uses": 3, + "reputation_discount": 0.2, + "wants": { + "count": 24, + "id": "minecraft:emerald" + }, + "xp": 15 +} diff --git a/src/main/resources/data/retold/villager_trade/progression/iron_leggings.json b/src/main/resources/data/retold/villager_trade/progression/iron_leggings.json new file mode 100644 index 0000000..55cdf9a --- /dev/null +++ b/src/main/resources/data/retold/villager_trade/progression/iron_leggings.json @@ -0,0 +1,12 @@ +{ + "gives": { + "id": "minecraft:iron_leggings" + }, + "max_uses": 3, + "reputation_discount": 0.2, + "wants": { + "count": 30, + "id": "minecraft:emerald" + }, + "xp": 15 +} diff --git a/src/main/resources/data/retold/villager_trade/progression/iron_pickaxe.json b/src/main/resources/data/retold/villager_trade/progression/iron_pickaxe.json new file mode 100644 index 0000000..9324ac7 --- /dev/null +++ b/src/main/resources/data/retold/villager_trade/progression/iron_pickaxe.json @@ -0,0 +1,12 @@ +{ + "gives": { + "id": "minecraft:iron_pickaxe" + }, + "max_uses": 3, + "reputation_discount": 0.2, + "wants": { + "count": 32, + "id": "minecraft:emerald" + }, + "xp": 15 +} diff --git a/src/main/resources/data/retold/villager_trade/progression/iron_shovel.json b/src/main/resources/data/retold/villager_trade/progression/iron_shovel.json new file mode 100644 index 0000000..28c15a8 --- /dev/null +++ b/src/main/resources/data/retold/villager_trade/progression/iron_shovel.json @@ -0,0 +1,12 @@ +{ + "gives": { + "id": "minecraft:iron_shovel" + }, + "max_uses": 3, + "reputation_discount": 0.2, + "wants": { + "count": 24, + "id": "minecraft:emerald" + }, + "xp": 15 +} diff --git a/src/main/resources/data/retold/villager_trade/progression/iron_spear.json b/src/main/resources/data/retold/villager_trade/progression/iron_spear.json new file mode 100644 index 0000000..483cd53 --- /dev/null +++ b/src/main/resources/data/retold/villager_trade/progression/iron_spear.json @@ -0,0 +1,12 @@ +{ + "gives": { + "id": "minecraft:iron_spear" + }, + "max_uses": 3, + "reputation_discount": 0.2, + "wants": { + "count": 30, + "id": "minecraft:emerald" + }, + "xp": 15 +} diff --git a/src/main/resources/data/retold/villager_trade/progression/iron_sword.json b/src/main/resources/data/retold/villager_trade/progression/iron_sword.json new file mode 100644 index 0000000..04ac57f --- /dev/null +++ b/src/main/resources/data/retold/villager_trade/progression/iron_sword.json @@ -0,0 +1,12 @@ +{ + "gives": { + "id": "minecraft:iron_sword" + }, + "max_uses": 3, + "reputation_discount": 0.2, + "wants": { + "count": 28, + "id": "minecraft:emerald" + }, + "xp": 15 +} From 3819273e7d0560514fe14750ff7bf54a841fcaa5 Mon Sep 17 00:00:00 2001 From: xefensor Date: Wed, 12 Aug 2026 01:37:18 +0200 Subject: [PATCH 06/11] Gate deepslate behind steel --- CHANGELOG.md | 2 +- docs/internal/design_implementation_status.md | 2 +- docs/internal/retold_mod_system.md | 4 +- docs/internal/tool_armor_ore_progression.md | 32 +++++----- .../RetoldToolProgressionGameTests.java | 61 +++++++++++++++++++ .../tags/block/incorrect_for_copper_tool.json | 6 ++ .../tags/block/incorrect_for_gold_tool.json | 6 ++ .../tags/block/incorrect_for_iron_tool.json | 6 ++ .../tags/block/incorrect_for_stone_tool.json | 6 ++ .../tags/block/incorrect_for_wooden_tool.json | 6 ++ .../block/incorrect_for_flint_multi_tool.json | 1 + .../retold/tags/block/steel_tier_blocks.json | 12 ++++ 12 files changed, 127 insertions(+), 17 deletions(-) create mode 100644 src/main/resources/data/minecraft/tags/block/incorrect_for_copper_tool.json create mode 100644 src/main/resources/data/minecraft/tags/block/incorrect_for_gold_tool.json create mode 100644 src/main/resources/data/minecraft/tags/block/incorrect_for_iron_tool.json create mode 100644 src/main/resources/data/minecraft/tags/block/incorrect_for_stone_tool.json create mode 100644 src/main/resources/data/minecraft/tags/block/incorrect_for_wooden_tool.json diff --git a/CHANGELOG.md b/CHANGELOG.md index b1ccecc..68fdfcd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ Each release should be readable in two passes: - The survival opening now begins with Sticks and Flint instead of punching logs. Leaves have an additional 20% chance to drop 1–2 Sticks, increasing by five percentage points per Fortune level; Dead Bushes drop 2–4 Sticks, while living Bush, Firefly Bush, Rose Bush, and Sweet Berry Bush blocks have a 10% chance to drop one. Shears and Silk Touch preserve the relevant blocks without extra Sticks. Logs require a suitable tool, the 2x2 Flint Multi-tool harvests the first wood, exposed Copper, and soft early stone, and vanilla Wooden and Stone tool recipes no longer bypass the material ladder. Copper generation now makes six vein attempts per chunk instead of sixteen while preserving normal vein sizes, reducing cave-wall clutter without making each discovery unrewarding. Copper Pickaxes can harvest normal Stone for Cobblestone, but do so at 25% speed until Iron makes ordinary mining practical. - Campfires are now crafted from three Sticks and three Logs without Coal or Flint and begin unlit immediately when placed, without briefly flashing their lit appearance. Using a bare Flint lights one and consumes that Flint in Survival, while Flint and Steel retains its normal durability-based ignition. Clay Balls fire into Bricks on a Campfire; eight Bricks in a ring then craft the Brick Furnace, Retold's renamed Smoker. It keeps food cooking, makes Charcoal from burnable logs, and processes Raw Copper and both Copper ores so players can reach Copper before obtaining Cobblestone for a normal Furnace. -- Blast Furnaces now process Iron Ingots directly into Steel Ingots using any ordinary fuel. The Spear now follows Flint, Copper, Iron, Steel, and Diamond progression, with new Flint and Steel Spears using provisional Stone and Iron visuals. Steel provides a full Pickaxe, Axe, Shovel, Hoe, Sword, Spear, and armor tier between Iron and Diamond. Copper and Iron remain painfully slow on Deepslate-family blocks, while Steel restores full deep-mining speed, harvests deep Diamond Ore, and still leaves Obsidian and Ancient Debris to Diamond. +- Blast Furnaces now process Iron Ingots directly into Steel Ingots using any ordinary fuel. The Spear now follows Flint, Copper, Iron, Steel, and Diamond progression, with new Flint and Steel Spears using provisional Stone and Iron visuals. Steel provides a full Pickaxe, Axe, Shovel, Hoe, Sword, Spear, and armor tier between Iron and Diamond. Pre-Steel tools cannot harvest Deepslate-family blocks or Deepslate ores; Copper and Iron also break them painfully slowly. Steel unlocks full deep mining and deep Diamond Ore, while Obsidian and Ancient Debris remain locked to Diamond. - Alternative equipment acquisition now follows fixed world rules in single-player and multiplayer. Bonus chests provide one Flint Multi-tool instead of Wooden/Stone tools; safe Village smith chests stop at Copper equipment and at most two Iron Ingots. Smith equipment trades unlock Copper at Apprentice for 8–12 Emeralds, Iron at Expert for 24–32, and Diamond at Master for 48–64, with enchanted Diamond offers rarer than unenchanted ones. The Wandering Trader retains its rare enchanted Iron Pickaxe at an enchantment-adjusted price around 48 Emeralds. - Mending can no longer be newly generated by Librarian trades or random loot. Existing Mending items continue to function, and commands and Creative mode retain the enchantment. - Unenchanted Diamond tools and Spears now have only 64 durability, while unenchanted Diamond armor has leather-like 6x durability. Diamond Horse and Nautilus Armor now use 96 durability before enchanting and 528 afterward, and lose durability from real hits like other armor. Any enchantment immediately restores full Diamond durability; removing every enchantment makes the item fragile again. A heavily damaged item stripped beyond that fragile limit retains one final use instead of becoming invalid immediately. diff --git a/docs/internal/design_implementation_status.md b/docs/internal/design_implementation_status.md index 76f71a4..f110cd0 100644 --- a/docs/internal/design_implementation_status.md +++ b/docs/internal/design_implementation_status.md @@ -166,7 +166,7 @@ Largest missing or partial design areas: | Wood cannot be obtained by hand | Implemented / needs in-game verification | A harvest check prevents logs from dropping unless the held item is a correct harvesting tool. Focused GameTest coverage verifies hand denial and Flint Multi-tool success; naturally verify block breaking, drops, Adventure mode, and common modded logs. | | Flint multi-tool | Implemented / needs in-game verification | The 2x2 two-Flint/one-Stick recipe, 48-durability combined axe/shovel/primitive Copper tool, repair tag, creative placement, language entry, and provisional vanilla-Flint model are implemented. Focused GameTests verify the recipe, durability, logs, normal Copper Ore, Tuff, and Stone denial. Natural survival pacing and visuals remain unverified. | | Reduced Copper generation | Implemented / needs fresh-world verification | Both `minecraft:ore_copper` and `minecraft:ore_copper_large` now make six placement attempts per chunk instead of sixteen, a 62.5% frequency reduction. Vanilla size-10 ordinary and size-20 Dripstone veins plus their height distribution are preserved. A focused registry-backed GameTest verifies both loaded overrides across three seeded origins spanning a chunk border; several fresh seeds, cave-wall exposure, and existing-versus-new chunk behavior still need natural verification. | -| Flint/copper/iron/steel/diamond tool progression | Partial / needs verification | Progression is implemented through Diamond: Wooden/Stone recipes are removed, Copper and Steel geology pacing is active, Spears now follow Flint/Copper/Iron/Steel/Diamond, and unenchanted tagged Diamond tools/Spear use 64 durability while any enchantment restores their vanilla maximum. Removing every enchantment makes them fragile again. Focused tests cover the boundaries, Spear recipes/tags, and transitions. Netherite/Aenderite equipment and final balance remain incomplete. | +| Flint/copper/iron/steel/diamond tool progression | Partial / needs verification | Progression is implemented through Diamond: Wooden/Stone recipes are removed, Copper unlocks slow Stone harvesting, Deepslate-family blocks and ores require Steel or better, Spears follow Flint/Copper/Iron/Steel/Diamond, and unenchanted tagged Diamond tools/Spear use 64 durability while any enchantment restores their vanilla maximum. Removing every enchantment makes them fragile again. Focused tests cover the boundaries, Spear recipes/tags, and transitions. Netherite/Aenderite equipment and final balance remain incomplete. | | Campfire, Brick Furnace, Furnace, Blast Furnace, and parallel enchanting progression | Partial / needs verification | Campfires use a fuel-free three-Stick/three-Log recipe. Their initial placement state is unlit on both logical sides, avoiding the former client-visible lit-state flash. Bare Flint ignites one and is consumed in Survival; Flint and Steel retains normal durability use. Campfire cooking fires Clay Balls into Bricks, and eight Bricks craft the Smoker-backed Brick Furnace. The Brick and normal Furnace roles are implemented. Per the 2026-08-11 choice, a standard 100-tick blasting recipe converts one Iron Ingot to one Steel Ingot while accepting ordinary Blast Furnace fuels; Charcoal is valid but not mandatory or fixed 1:1. Blast Furnace construction remains vanilla. Enchanting follows the separate deterministic SGA system. | | Leather/copper/iron/steel/diamond armor progression | Partial / needs verification | Steel has its provisionally balanced four-piece set. Unenchanted Diamond player armor uses 6x durability (66/96/90/78), while any enchantment restores 33x durability and removing all enchantments restores fragility. Diamond Horse and Nautilus Armor now follow the BODY/Chestplate 96/528 durability transition and take wear from real hits; non-Diamond animal armor remains indestructible. All twelve Wolf, Horse, and Nautilus Armor items support the exact Chestplate enchantment set and use their material's enchantability value. Focused equipped-animal tests cover damage wear, Protection-family mitigation, Fire Protection burn duration, Thorns, Unbreaking, Mending, Binding, and Vanishing paths. Retold bridges protection into Wolf Armor's special absorbed-durability path, while Horse and Nautilus armor use vanilla health mitigation. Later Retold armor tiers remain incomplete. | | Diamond tools weak unless enchanted | Implemented / needs in-game verification | A narrow `ItemStack` hook delegates to `RetoldDiamondDurability`; all twelve enchantable Diamond items use fragile unenchanted durability and their full maximum while enchanted. Stripping a heavily damaged item preserves its damage and leaves one final use rather than an invalid stack. Focused coverage enumerates the complete set, verifies enchant/remove transitions and the damaged-item edge case, and confirms Diamond Horse/Nautilus Armor wear on real hits. | diff --git a/docs/internal/retold_mod_system.md b/docs/internal/retold_mod_system.md index beec926..8cafcda 100644 --- a/docs/internal/retold_mod_system.md +++ b/docs/internal/retold_mod_system.md @@ -138,7 +138,9 @@ order is dependency-aware: faction precedes territory, and territory precedes be `RetoldToolProgressionEvents` owns the non-data opening rules: logs require a correct held tool, the Copper Pickaxe receives a Stone-specific speed penalty, Copper and Iron Pickaxes receive the Steel-tier Deepslate penalty, and exact vanilla Wooden/Stone tool recipes are removed during recipe -JSON modification. `RetoldLeafStickLootModifier`, registered through `RetoldLootModifiers`, gives +JSON modification. Tool-material correctness tags deny Deepslate-family drops to every pre-Steel +material while allowing Steel and later tiers to harvest them. `RetoldLeafStickLootModifier`, +registered through `RetoldLootModifiers`, gives every `minecraft:leaves` block a supplemental 20% roll for 1–2 Sticks, increasing five percentage points per Fortune level. It also normalizes Dead Bushes to 2–4 Sticks and gives tagged living bushes a 10% one-Stick roll, while excluding shears and Silk Touch. `RetoldBlocks` registers the diff --git a/docs/internal/tool_armor_ore_progression.md b/docs/internal/tool_armor_ore_progression.md index 462a868..61dbf67 100644 --- a/docs/internal/tool_armor_ore_progression.md +++ b/docs/internal/tool_armor_ore_progression.md @@ -18,7 +18,9 @@ Leather -> Copper -> Iron -> Steel -> Diamond -> Netherite -> Aenderite Copper and Steel both receive full normal tool and armor sets. Standard tool families from Copper onward should follow the same familiar material ladder for simplicity, including pickaxe, axe, shovel, hoe, and sword unless a later feature-specific redesign says otherwise. -Gold is deliberately outside this progression for now and will receive a separate design pass because of its Nether/Pigman/lore role. +Gold remains outside the required progression as an optional post-Iron sidegrade. It keeps its +vanilla identity: exceptionally fast but fragile tools, high enchantability, and armor utility for +Piglin interaction. Gold does not gate Steel or Diamond. ## Design Goal @@ -113,7 +115,9 @@ but the recipe does not require it specifically or consume it at a fixed 1:1 rat normally power a Blast Furnace remain valid. This intentionally accepts vanilla's fuel efficiency instead of adding custom fuel-slot logic. -Blast Furnace construction should broadly preserve the old Retold direction of requiring advanced masonry/metal materials such as bricks and iron, while staying visually/readably close to normal Minecraft crafting. Exact recipe remains to be finalized. +The Blast Furnace keeps its vanilla crafting recipe: five Iron Ingots, one Furnace, and three +Smooth Stone. Requiring both the Furnace and Furnace-made Smooth Stone preserves the station +progression without adding another custom recipe. ### Enchanting Table @@ -316,14 +320,16 @@ copying or modifying Minecraft textures. ### Steel mining identity -Steel is the tier that makes **Deepslate** practically mineable and opens the deepest Overworld geology. +Steel is the tier that unlocks **Deepslate** harvesting and opens the deepest Overworld geology. -Copper and Iron Pickaxes can still harvest applicable Deepslate-family blocks, but do so at 25% -of their otherwise calculated speed. The data-driven Steel-tier list contains natural Deepslate, -its construction variants, and Deepslate ores. Steel mines them at its full speed, can harvest -Deepslate Diamond Ore, and still cannot harvest Obsidian, preserving Diamond's next access step. +Copper and Iron Pickaxes break Deepslate-family blocks at 25% of their otherwise calculated speed +but receive no drops. Wooden, Stone, Gold, Copper, Iron, and Flint tools all treat the data-driven +Steel-tier list as incorrect for drops. That list contains natural Deepslate, its construction +variants, and Deepslate ores. Steel mines and harvests them at its full speed, can harvest Deepslate +Diamond Ore, and still cannot harvest Obsidian, preserving Diamond's next access step. Diamond and +Netherite retain Deepslate harvesting after Steel. -This naturally gates practical Diamond access behind Steel because modern vanilla Diamond generation strongly favors deep/deepslate regions. +This hard-gates deep Diamond access behind Steel. Keep vanilla Diamond generation initially; let geological access provide the progression gate. @@ -337,7 +343,7 @@ Diamond equipment is a high-end magical material and is intentionally dependent ```text Steel --> practical Deepslate mining +-> unlock Deepslate harvesting -> reach Diamond-rich deep layers -> mine Diamond ``` @@ -443,7 +449,7 @@ Iron Ingot + ordinary Blast Furnace fuel -> Blast Furnace -> Steel Ingot -> Steel tools/armor --> Deepslate becomes practical +-> Deepslate harvesting unlocks Deep mining -> Diamond @@ -545,7 +551,7 @@ Copper rate again only from concrete natural-world results. - Copper Pickaxe can mine Stone and obtain Cobblestone, but does so slowly. - Iron makes Stone mining practical. - Steel is produced by blasting Iron Ingots; Charcoal is an ordinary valid fuel rather than a required second ingredient. -- Steel makes Deepslate practical and thereby opens deep Diamond progression. +- Pre-Steel tools cannot harvest Deepslate-family blocks or ores; Steel unlocks them and thereby opens deep Diamond progression. - Ancient Debris remains in the Diamond harvest tier. - Copper and Steel receive full tool and armor sets. - Standard tool families follow the same tier ladder from Copper onward. @@ -554,16 +560,14 @@ Copper rate again only from concrete natural-world results. - Netherite sits between Diamond and Aenderite and upgrades Diamond equipment. - Aenderite is the final exotic tier but must have an identity beyond bigger stats. - Keep vanilla Iron and Diamond generation; Copper is the confirmed exception at six vein attempts per chunk with vanilla vein sizes. -- Gold is intentionally deferred to a separate design pass. +- Gold is an optional post-Iron sidegrade and does not gate Steel or Diamond. - Mending is excluded from new random loot and Librarian trades, but remains registered and functional on existing or command/Creative-created items. ## Still Undecided -- exact Blast Furnace crafting recipe if Retold changes vanilla's recipe - final tool mining speeds and durability per tier beyond the provisional Flint, Copper, Steel, and unenchanted Diamond values - final armor/combat stats beyond the provisional Steel and unenchanted Diamond values - exact block/tag harvest lists beyond the implemented Flint and Steel-tier opening boundaries -- exact role and progression position of Gold - whether Smithing Table remains or Netherite upgrade functionality moves into the Anvil - exact Aenderite crafting/upgrading method and special abilities - whether later nonstandard tools/weapons follow different material rules after the future combat/tool audit diff --git a/src/main/java/cz/xefensor/retold/progression/RetoldToolProgressionGameTests.java b/src/main/java/cz/xefensor/retold/progression/RetoldToolProgressionGameTests.java index 042a3ce..2559c5c 100644 --- a/src/main/java/cz/xefensor/retold/progression/RetoldToolProgressionGameTests.java +++ b/src/main/java/cz/xefensor/retold/progression/RetoldToolProgressionGameTests.java @@ -667,6 +667,54 @@ private static void harvestRulesEnforceMaterialLadder( ironDeepslateSpeed.getNewSpeed() == 1.5F, "Iron must mine Deepslate at 25% speed before Steel" ); + helper.assertFalse( + flintMultiTool.isCorrectToolForDrops( + Blocks.DEEPSLATE.defaultBlockState() + ), + "Flint must not harvest Deepslate" + ); + helper.assertFalse( + Items.WOODEN_PICKAXE.getDefaultInstance() + .isCorrectToolForDrops( + Blocks.DEEPSLATE.defaultBlockState() + ), + "Wood must not harvest Deepslate" + ); + helper.assertFalse( + Items.STONE_PICKAXE.getDefaultInstance() + .isCorrectToolForDrops( + Blocks.DEEPSLATE.defaultBlockState() + ), + "Stone must not harvest Deepslate" + ); + helper.assertFalse( + Items.COPPER_PICKAXE.getDefaultInstance() + .isCorrectToolForDrops( + Blocks.DEEPSLATE.defaultBlockState() + ), + "Copper must not harvest Deepslate" + ); + helper.assertFalse( + Items.IRON_PICKAXE.getDefaultInstance() + .isCorrectToolForDrops( + Blocks.DEEPSLATE_IRON_ORE.defaultBlockState() + ), + "Iron must not harvest Deepslate ores" + ); + helper.assertFalse( + Items.GOLDEN_PICKAXE.getDefaultInstance() + .isCorrectToolForDrops( + Blocks.DEEPSLATE.defaultBlockState() + ), + "Gold must remain a sidegrade and not bypass Steel" + ); + helper.assertFalse( + Items.IRON_PICKAXE.getDefaultInstance() + .isCorrectToolForDrops( + Blocks.DEEPSLATE_TILE_STAIRS.defaultBlockState() + ), + "Iron must not harvest constructed Deepslate variants" + ); ItemStack steelPickaxe = new ItemStack( RetoldBlocks.STEEL_PICKAXE.get() @@ -684,12 +732,25 @@ private static void harvestRulesEnforceMaterialLadder( steelDeepslateSpeed.getNewSpeed() == 7.0F, "Steel must make Deepslate practical" ); + helper.assertTrue( + steelPickaxe.isCorrectToolForDrops( + Blocks.DEEPSLATE.defaultBlockState() + ), + "Steel must unlock Deepslate harvesting" + ); helper.assertTrue( steelPickaxe.isCorrectToolForDrops( Blocks.DEEPSLATE_DIAMOND_ORE.defaultBlockState() ), "Steel must harvest deep Diamond ore" ); + helper.assertTrue( + Items.DIAMOND_PICKAXE.getDefaultInstance() + .isCorrectToolForDrops( + Blocks.DEEPSLATE.defaultBlockState() + ), + "Diamond must retain Deepslate harvesting after Steel" + ); helper.assertFalse( steelPickaxe.isCorrectToolForDrops( Blocks.OBSIDIAN.defaultBlockState() diff --git a/src/main/resources/data/minecraft/tags/block/incorrect_for_copper_tool.json b/src/main/resources/data/minecraft/tags/block/incorrect_for_copper_tool.json new file mode 100644 index 0000000..1dba507 --- /dev/null +++ b/src/main/resources/data/minecraft/tags/block/incorrect_for_copper_tool.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "#retold:steel_tier_blocks" + ] +} diff --git a/src/main/resources/data/minecraft/tags/block/incorrect_for_gold_tool.json b/src/main/resources/data/minecraft/tags/block/incorrect_for_gold_tool.json new file mode 100644 index 0000000..1dba507 --- /dev/null +++ b/src/main/resources/data/minecraft/tags/block/incorrect_for_gold_tool.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "#retold:steel_tier_blocks" + ] +} diff --git a/src/main/resources/data/minecraft/tags/block/incorrect_for_iron_tool.json b/src/main/resources/data/minecraft/tags/block/incorrect_for_iron_tool.json new file mode 100644 index 0000000..1dba507 --- /dev/null +++ b/src/main/resources/data/minecraft/tags/block/incorrect_for_iron_tool.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "#retold:steel_tier_blocks" + ] +} diff --git a/src/main/resources/data/minecraft/tags/block/incorrect_for_stone_tool.json b/src/main/resources/data/minecraft/tags/block/incorrect_for_stone_tool.json new file mode 100644 index 0000000..1dba507 --- /dev/null +++ b/src/main/resources/data/minecraft/tags/block/incorrect_for_stone_tool.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "#retold:steel_tier_blocks" + ] +} diff --git a/src/main/resources/data/minecraft/tags/block/incorrect_for_wooden_tool.json b/src/main/resources/data/minecraft/tags/block/incorrect_for_wooden_tool.json new file mode 100644 index 0000000..1dba507 --- /dev/null +++ b/src/main/resources/data/minecraft/tags/block/incorrect_for_wooden_tool.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "#retold:steel_tier_blocks" + ] +} diff --git a/src/main/resources/data/retold/tags/block/incorrect_for_flint_multi_tool.json b/src/main/resources/data/retold/tags/block/incorrect_for_flint_multi_tool.json index f7054f2..e756ff1 100644 --- a/src/main/resources/data/retold/tags/block/incorrect_for_flint_multi_tool.json +++ b/src/main/resources/data/retold/tags/block/incorrect_for_flint_multi_tool.json @@ -1,5 +1,6 @@ { "values": [ + "#retold:steel_tier_blocks", "#minecraft:needs_iron_tool", "#minecraft:needs_diamond_tool" ] diff --git a/src/main/resources/data/retold/tags/block/steel_tier_blocks.json b/src/main/resources/data/retold/tags/block/steel_tier_blocks.json index 1a06fa4..33bce5b 100644 --- a/src/main/resources/data/retold/tags/block/steel_tier_blocks.json +++ b/src/main/resources/data/retold/tags/block/steel_tier_blocks.json @@ -2,11 +2,23 @@ "values": [ "minecraft:deepslate", "minecraft:cobbled_deepslate", + "minecraft:cobbled_deepslate_slab", + "minecraft:cobbled_deepslate_stairs", + "minecraft:cobbled_deepslate_wall", "minecraft:polished_deepslate", + "minecraft:polished_deepslate_slab", + "minecraft:polished_deepslate_stairs", + "minecraft:polished_deepslate_wall", "minecraft:chiseled_deepslate", "minecraft:deepslate_bricks", + "minecraft:deepslate_brick_slab", + "minecraft:deepslate_brick_stairs", + "minecraft:deepslate_brick_wall", "minecraft:cracked_deepslate_bricks", "minecraft:deepslate_tiles", + "minecraft:deepslate_tile_slab", + "minecraft:deepslate_tile_stairs", + "minecraft:deepslate_tile_wall", "minecraft:cracked_deepslate_tiles", "minecraft:reinforced_deepslate", "minecraft:deepslate_coal_ore", From 93e21f7736839410f6445ac329a06ad26cde8d37 Mon Sep 17 00:00:00 2001 From: xefensor Date: Wed, 12 Aug 2026 22:25:33 +0200 Subject: [PATCH 07/11] Document curse durability behavior --- CHANGELOG.md | 2 +- docs/internal/design_implementation_status.md | 2 +- docs/internal/retold_design_risks.md | 2 +- docs/internal/retold_mod_system.md | 4 ++-- docs/internal/tool_armor_ore_progression.md | 4 +++- .../progression/RetoldToolProgressionGameTests.java | 12 ++++++++++++ 6 files changed, 20 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 68fdfcd..456dcb6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,7 +16,7 @@ Each release should be readable in two passes: - Blast Furnaces now process Iron Ingots directly into Steel Ingots using any ordinary fuel. The Spear now follows Flint, Copper, Iron, Steel, and Diamond progression, with new Flint and Steel Spears using provisional Stone and Iron visuals. Steel provides a full Pickaxe, Axe, Shovel, Hoe, Sword, Spear, and armor tier between Iron and Diamond. Pre-Steel tools cannot harvest Deepslate-family blocks or Deepslate ores; Copper and Iron also break them painfully slowly. Steel unlocks full deep mining and deep Diamond Ore, while Obsidian and Ancient Debris remain locked to Diamond. - Alternative equipment acquisition now follows fixed world rules in single-player and multiplayer. Bonus chests provide one Flint Multi-tool instead of Wooden/Stone tools; safe Village smith chests stop at Copper equipment and at most two Iron Ingots. Smith equipment trades unlock Copper at Apprentice for 8–12 Emeralds, Iron at Expert for 24–32, and Diamond at Master for 48–64, with enchanted Diamond offers rarer than unenchanted ones. The Wandering Trader retains its rare enchanted Iron Pickaxe at an enchantment-adjusted price around 48 Emeralds. - Mending can no longer be newly generated by Librarian trades or random loot. Existing Mending items continue to function, and commands and Creative mode retain the enchantment. -- Unenchanted Diamond tools and Spears now have only 64 durability, while unenchanted Diamond armor has leather-like 6x durability. Diamond Horse and Nautilus Armor now use 96 durability before enchanting and 528 afterward, and lose durability from real hits like other armor. Any enchantment immediately restores full Diamond durability; removing every enchantment makes the item fragile again. A heavily damaged item stripped beyond that fragile limit retains one final use instead of becoming invalid immediately. +- Unenchanted Diamond tools and Spears now have only 64 durability, while unenchanted Diamond armor has leather-like 6x durability. Diamond Horse and Nautilus Armor now use 96 durability before enchanting and 528 afterward, and lose durability from real hits like other armor. Any enchantment—including a curse by itself—immediately restores full Diamond durability; removing every enchantment makes the item fragile again. A heavily damaged item stripped beyond that fragile limit retains one final use instead of becoming invalid immediately. - Wolf Armor and every Horse and Nautilus Armor material can now be enchanted with the same enchantment pool as a Chestplate. Each uses the enchanting value of its own armor material. Protection enchantments now affect damage absorbed by Wolf Armor as well as ordinary animal health damage; Fire Protection also retains its normal shorter-burning effect. - The End no longer produces its periodic celestial flashes, temporary brightness pulses, or delayed flash sounds. Retold's generated End sky remains unchanged. - Trial Chambers, Ancient Cities, and the Deep Dark no longer generate in newly explored terrain. Their blocks, items, mobs, biomes, and already-generated content remain available. diff --git a/docs/internal/design_implementation_status.md b/docs/internal/design_implementation_status.md index f110cd0..ccaff18 100644 --- a/docs/internal/design_implementation_status.md +++ b/docs/internal/design_implementation_status.md @@ -169,7 +169,7 @@ Largest missing or partial design areas: | Flint/copper/iron/steel/diamond tool progression | Partial / needs verification | Progression is implemented through Diamond: Wooden/Stone recipes are removed, Copper unlocks slow Stone harvesting, Deepslate-family blocks and ores require Steel or better, Spears follow Flint/Copper/Iron/Steel/Diamond, and unenchanted tagged Diamond tools/Spear use 64 durability while any enchantment restores their vanilla maximum. Removing every enchantment makes them fragile again. Focused tests cover the boundaries, Spear recipes/tags, and transitions. Netherite/Aenderite equipment and final balance remain incomplete. | | Campfire, Brick Furnace, Furnace, Blast Furnace, and parallel enchanting progression | Partial / needs verification | Campfires use a fuel-free three-Stick/three-Log recipe. Their initial placement state is unlit on both logical sides, avoiding the former client-visible lit-state flash. Bare Flint ignites one and is consumed in Survival; Flint and Steel retains normal durability use. Campfire cooking fires Clay Balls into Bricks, and eight Bricks craft the Smoker-backed Brick Furnace. The Brick and normal Furnace roles are implemented. Per the 2026-08-11 choice, a standard 100-tick blasting recipe converts one Iron Ingot to one Steel Ingot while accepting ordinary Blast Furnace fuels; Charcoal is valid but not mandatory or fixed 1:1. Blast Furnace construction remains vanilla. Enchanting follows the separate deterministic SGA system. | | Leather/copper/iron/steel/diamond armor progression | Partial / needs verification | Steel has its provisionally balanced four-piece set. Unenchanted Diamond player armor uses 6x durability (66/96/90/78), while any enchantment restores 33x durability and removing all enchantments restores fragility. Diamond Horse and Nautilus Armor now follow the BODY/Chestplate 96/528 durability transition and take wear from real hits; non-Diamond animal armor remains indestructible. All twelve Wolf, Horse, and Nautilus Armor items support the exact Chestplate enchantment set and use their material's enchantability value. Focused equipped-animal tests cover damage wear, Protection-family mitigation, Fire Protection burn duration, Thorns, Unbreaking, Mending, Binding, and Vanishing paths. Retold bridges protection into Wolf Armor's special absorbed-durability path, while Horse and Nautilus armor use vanilla health mitigation. Later Retold armor tiers remain incomplete. | -| Diamond tools weak unless enchanted | Implemented / needs in-game verification | A narrow `ItemStack` hook delegates to `RetoldDiamondDurability`; all twelve enchantable Diamond items use fragile unenchanted durability and their full maximum while enchanted. Stripping a heavily damaged item preserves its damage and leaves one final use rather than an invalid stack. Focused coverage enumerates the complete set, verifies enchant/remove transitions and the damaged-item edge case, and confirms Diamond Horse/Nautilus Armor wear on real hits. | +| Diamond tools weak unless enchanted | Implemented / needs in-game verification | A narrow `ItemStack` hook delegates to `RetoldDiamondDurability`; all twelve enchantable Diamond items use fragile unenchanted durability and their full maximum while enchanted. Any enchantment qualifies, including a curse as the item's only enchantment. Stripping a heavily damaged item preserves its damage and leaves one final use rather than an invalid stack. Focused coverage enumerates the complete set, verifies ordinary-enchantment, curse-only, removal, and damaged-item transitions, and confirms Diamond Horse/Nautilus Armor wear on real hits. | | Aenderite ore and refined material | Partial / needs verification | Aenderite generates at diamond-like abundance inside Aender Stone, using mostly 3–4 and 4–8 block veins with rare 8–12 block veins, biased toward island undersides. A Netherite Pickaxe is required; Silk Touch preserves the ore, Fortune applies to Raw Aenderite, and raw material smelts/blasts into an ingot. Tools, armor, blocks, and other ingot uses are intentionally not designed yet. | | Enchanting rework | Partial / needs interaction verification | All 43 currently registered enchantments have unique data-driven `domain + effect + modifier` definitions using the fixed 26-concept SGA vocabulary. Duplicate enchantment/word mappings and unknown concepts are rejected atomically, and the validated catalog is synchronized to clients on join and datapack reload. Known enchantment ids persist per player and each receiving client gets its server-authoritative knowledge snapshot. Completed anvil use teaches only book enchantments that actually increased the result compared with the left input. Unknown mapped tooltip entries show only SGA plus level; known entries retain their readable name and add the SGA word. The developer confirmed tooltip behavior and accepted the current table layout in-game on 2026-08-09. The deterministic table transaction, item-aware known-spell filtering, registered maximum display/limits, green success clearing/highlight, and generic low-note/red-highlight rejection cue are implemented with focused coverage. The newest filtering/feedback interaction and dedicated multiplayer synchronization still need verification. | | Iron rods/sticks crafting changes | Not implemented | diff --git a/docs/internal/retold_design_risks.md b/docs/internal/retold_design_risks.md index 1a3246c..71c6f0e 100644 --- a/docs/internal/retold_design_risks.md +++ b/docs/internal/retold_design_risks.md @@ -33,7 +33,7 @@ | Villages | Container, Farmer-crop, and profession-tended livestock offenses use witnessed vanilla gossip. Sight and village-context checks can be sensitive to walls, crowded settlements, vertical farms, merged double chests, animal transport, automation, and multiplayer timing. | Generated village loot plus Villager-produced quantities are protected; player deposits and ambiguous already-opened existing-world contents are not. Farmer planting/replanting marks persistent crop positions. Shepherds, Leatherworkers, and Butchers claim only animals they successfully feed with two real storage items; player interaction/leashing marks previously unowned livestock as player-associated. Offspring of two owned parents inherit persisted village ownership, while an automatic offspring of a player-associated unowned parent inherits player protection. Witnessed direct Survival kills add `-50`; monsters, environment, Creative, and Spectator do not. Four focused animal tests plus the crop/container groups cover persistence, ownership separation, conservation, offense strengths, witnesses, and exclusions; the latest 50-Villager TPS peak is 6.864 ms/tick. Naturally verify physical storage-to-pen routes, wandering/boat-transport edge cases, full harvest/replant cycles, trade prices, golem reaction, double chests, hoppers, simultaneous players, dedicated servers, and existing worlds before calling the loop fully verified. | | Stage 3 | Raid creation is now gated to Stage 3, but the broader illager behavior may need clearer player-facing feedback later. | Avoid major raid redesign without developer approval. The Stage 2 live creation rejection and Witch/Illager same-raid cooperation are regression-tested; natural Bad Omen preservation, Stage 3 Raid Omen conversion, wave participation, healing, and raid-exit behavior still need in-game verification. Existing raids deliberately continue if an administrative command moves the world back below Stage 3. | | Piglins | Stage 3 piglin/pigman hiring or follower behavior is planned but not implemented. | Needs feature design. | -| Items | The implemented Flint-through-Diamond spine changes first-spawn assumptions, leaf/bush loot, chest and Villager alternatives, Mending acquisition, Copper distribution, Campfire ignition, recipes, station use, mining speed, Flint/Steel Spears, ten Steel equipment items, animal-armor enchanting, and the effective maximum durability of existing Diamond equipment. Its provisional balance, fuel economy, compatibility, and reused visuals need validation. Later equipment and combat reworks remain planned. | Focused GameTests cover the material ladder through Steel, six-attempt ordinary/large Copper placement across seeded chunk-border origins, scaled leaf/Dead Bush/living-bush Stick rolls and harvest exclusions, Flint/Steel Spear recipes/tags, bonus and Village chest ceilings, mastery/price trade tiers, enchanted trade rarity, Wandering Trader pricing, Mending source tags, Campfire/Brick Furnace boundaries, all twelve enchantable Diamond items, and animal-armor enchant effects. Chest/trade/enchantment overrides are global server data and therefore consistent across players, but existing saved Villager offers are deliberately not rerolled and datapacks may replace the same tables/tags. Naturally verify new and existing worlds, Villager leveling/discounts/restocking, multiplayer/dedicated servers, every chest type, fishing and structure Mending absence, bush farming, Spear combat/repair/enchanting, reused visuals, fresh-seed Copper pacing, Campfire visuals/automation, Steel fuel economy, and dynamic Diamond durability. Existing Mending items remain functional, and commands/Creative retain access. Aenderite still provides only an ore/raw/ingot foundation. | +| Items | The implemented Flint-through-Diamond spine changes first-spawn assumptions, leaf/bush loot, chest and Villager alternatives, Mending acquisition, Copper distribution, Campfire ignition, recipes, station use, mining speed, Flint/Steel Spears, ten Steel equipment items, animal-armor enchanting, and the effective maximum durability of existing Diamond equipment. Its provisional balance, fuel economy, compatibility, and reused visuals need validation. Later equipment and combat reworks remain planned. | Focused GameTests cover the material ladder through Steel, six-attempt ordinary/large Copper placement across seeded chunk-border origins, scaled leaf/Dead Bush/living-bush Stick rolls and harvest exclusions, Flint/Steel Spear recipes/tags, bonus and Village chest ceilings, mastery/price trade tiers, enchanted trade rarity, Wandering Trader pricing, Mending source tags, Campfire/Brick Furnace boundaries, all twelve enchantable Diamond items including a curse-only durability unlock, and animal-armor enchant effects. Curses intentionally count as enchantments, but revisit that choice if curse acquisition makes full Diamond durability too cheap. Chest/trade/enchantment overrides are global server data and therefore consistent across players, but existing saved Villager offers are deliberately not rerolled and datapacks may replace the same tables/tags. Naturally verify new and existing worlds, Villager leveling/discounts/restocking, multiplayer/dedicated servers, every chest type, fishing and structure Mending absence, bush farming, Spear combat/repair/enchanting, reused visuals, fresh-seed Copper pacing, Campfire visuals/automation, Steel fuel economy, and dynamic Diamond durability. Existing Mending items remain functional, and commands/Creative retain access. Aenderite still provides only an ore/raw/ingot foundation. | | Environment | Death drops should despawn much later than vanilla, not never. | No implementation confirmed. | | Beds | Beds should not skip night; valid daytime bed rest is allowed when night skipping is disabled. | Healing behavior not confirmed implemented. | | Nether | Nether portal spread is planned as energy drain. | Needs bounded implementation design. | diff --git a/docs/internal/retold_mod_system.md b/docs/internal/retold_mod_system.md index 8cafcda..f7f38d3 100644 --- a/docs/internal/retold_mod_system.md +++ b/docs/internal/retold_mod_system.md @@ -166,8 +166,8 @@ saved offers and existing Mending items are deliberately not rewritten. is only the return-value hook for `ItemStack.getMaxDamage`; separate item tags identify affected Diamond tools/Spear and armor. Unenchanted tools use 64 durability and armor scales from vanilla's 33x to 6x. Diamond Horse and Nautilus Armor receive the BODY/Chestplate base of 528, producing 96 -unenchanted durability. Any enchantment restores the underlying full maximum, while removing all -enchantments restores fragility. Raw damage is read directly from the component so the hook cannot +unenchanted durability. Any enchantment, including a curse by itself, restores the underlying full +maximum, while removing all enchantments restores fragility. Raw damage is read directly from the component so the hook cannot re-enter itself; an over-cap stripped item receives an effective `damage + 1` maximum and one final use. A `LivingDamageEvent.Pre` handler gives those two BODY-slot items normal armor wear after a non-armor-bypassing hit; `ItemStack.hurtAndBreak` retains Unbreaking and break behavior. diff --git a/docs/internal/tool_armor_ore_progression.md b/docs/internal/tool_armor_ore_progression.md index 61dbf67..bf3b468 100644 --- a/docs/internal/tool_armor_ore_progression.md +++ b/docs/internal/tool_armor_ore_progression.md @@ -359,7 +359,8 @@ The developer chose dynamic durability on 2026-08-11: Leggings 90, and Boots 78 - unenchanted Diamond Horse and Nautilus Armor use the BODY/Chestplate value of 96 durability; enchanting either restores its full 528 durability -- while any enchantment is present, the item immediately uses its full vanilla Diamond durability +- while any enchantment is present, including a curse as the only enchantment, the item immediately + uses its full vanilla Diamond durability - removing every enchantment, including through a Grindstone, immediately restores the fragile maximum - if the preserved damage value already exceeds that fragile maximum, the effective maximum is @@ -556,6 +557,7 @@ Copper rate again only from concrete natural-world results. - Copper and Steel receive full tool and armor sets. - Standard tool families follow the same tier ladder from Copper onward. - Diamond equipment has very low durability until enchanted. +- Curses count as enchantments for Diamond durability, including curse-only equipment. - Diamond durability is dynamic: removing every enchantment makes tagged Diamond tools, player armor, Horse Armor, and Nautilus Armor fragile again. - Netherite sits between Diamond and Aenderite and upgrades Diamond equipment. - Aenderite is the final exotic tier but must have an identity beyond bigger stats. diff --git a/src/main/java/cz/xefensor/retold/progression/RetoldToolProgressionGameTests.java b/src/main/java/cz/xefensor/retold/progression/RetoldToolProgressionGameTests.java index 2559c5c..b0ba945 100644 --- a/src/main/java/cz/xefensor/retold/progression/RetoldToolProgressionGameTests.java +++ b/src/main/java/cz/xefensor/retold/progression/RetoldToolProgressionGameTests.java @@ -806,6 +806,18 @@ private static void harvestRulesEnforceMaterialLadder( diamondPickaxe.getMaxDamage() == 64, "Removing all enchantments must restore fragile durability" ); + diamondPickaxe.enchant( + enchantments.getOrThrow(Enchantments.VANISHING_CURSE), + 1 + ); + helper.assertTrue( + diamondPickaxe.getMaxDamage() == 1561, + "A curse alone must count as an enchantment and restore full Diamond durability" + ); + diamondPickaxe.set( + DataComponents.ENCHANTMENTS, + ItemEnchantments.EMPTY + ); diamondPickaxe.enchant( enchantments.getOrThrow(Enchantments.EFFICIENCY), From 6563182759bfe6fa95f6d5c3b35951db4e69b32e Mon Sep 17 00:00:00 2001 From: xefensor Date: Wed, 12 Aug 2026 22:28:28 +0200 Subject: [PATCH 08/11] Retain vanilla Netherite smithing --- docs/internal/design_implementation_status.md | 2 +- docs/internal/tool_armor_ore_progression.md | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/internal/design_implementation_status.md b/docs/internal/design_implementation_status.md index ccaff18..1cc057a 100644 --- a/docs/internal/design_implementation_status.md +++ b/docs/internal/design_implementation_status.md @@ -181,7 +181,7 @@ Largest missing or partial design areas: | Sword sweep on right-click | Not implemented | | XP/energy affects damage/defense | Not implemented | | Remove new Mending acquisition | Implemented / needs natural verification | Mending is excluded from `minecraft:tradeable` and `minecraft:on_random_loot`, removing new Librarian and random-loot generation. It remains registered for commands/Creative and continues functioning on existing items. Focused registry-tag coverage passes; naturally verify fishing, structure loot, Librarians, existing worlds, and datapack compatibility. | -| Smithing table removed/merged with anvil | Not implemented | +| Smithing Table removed/merged with Anvil | Deferred / vanilla retained | Netherite currently keeps the vanilla Smithing Table and Netherite Upgrade Smithing Template workflow. The older merge concept may be reconsidered only in a later station-design pass. | ## Recipe Discovery And Villagers diff --git a/docs/internal/tool_armor_ore_progression.md b/docs/internal/tool_armor_ore_progression.md index bf3b468..2679c08 100644 --- a/docs/internal/tool_armor_ore_progression.md +++ b/docs/internal/tool_armor_ore_progression.md @@ -129,7 +129,10 @@ The currently implemented deterministic SGA enchanting system governs its behavi Netherite should remain an upgrade to Diamond equipment rather than a separately crafted normal tool tier. -The exact station ownership between Smithing Table and Anvil can be revisited later because an older Retold note proposed folding Smithing Table functionality into the Anvil. Do not treat that old note as confirmed yet. +For the current progression, Netherite keeps vanilla's Smithing Table and Netherite Upgrade Smithing +Template workflow. An older Retold note proposed folding Smithing Table functionality into the +Anvil, but that is not part of the current implementation direction and may only be reconsidered +in a later station-design pass. ## Opening Progression @@ -560,6 +563,7 @@ Copper rate again only from concrete natural-world results. - Curses count as enchantments for Diamond durability, including curse-only equipment. - Diamond durability is dynamic: removing every enchantment makes tagged Diamond tools, player armor, Horse Armor, and Nautilus Armor fragile again. - Netherite sits between Diamond and Aenderite and upgrades Diamond equipment. +- Netherite currently keeps the vanilla Smithing Table and upgrade-template workflow. - Aenderite is the final exotic tier but must have an identity beyond bigger stats. - Keep vanilla Iron and Diamond generation; Copper is the confirmed exception at six vein attempts per chunk with vanilla vein sizes. - Gold is an optional post-Iron sidegrade and does not gate Steel or Diamond. @@ -570,6 +574,5 @@ Copper rate again only from concrete natural-world results. - final tool mining speeds and durability per tier beyond the provisional Flint, Copper, Steel, and unenchanted Diamond values - final armor/combat stats beyond the provisional Steel and unenchanted Diamond values - exact block/tag harvest lists beyond the implemented Flint and Steel-tier opening boundaries -- whether Smithing Table remains or Netherite upgrade functionality moves into the Anvil - exact Aenderite crafting/upgrading method and special abilities - whether later nonstandard tools/weapons follow different material rules after the future combat/tool audit From 234615ef798e4dfe18a5e2f65435dc739ecda34e Mon Sep 17 00:00:00 2001 From: xefensor Date: Wed, 12 Aug 2026 22:34:05 +0200 Subject: [PATCH 09/11] Require steel for all diamond ore --- CHANGELOG.md | 2 +- docs/internal/design_implementation_status.md | 2 +- docs/internal/retold_mod_system.md | 6 ++++-- docs/internal/tool_armor_ore_progression.md | 13 +++++++------ .../RetoldToolProgressionGameTests.java | 15 ++++++++++++++- .../tags/block/incorrect_for_copper_tool.json | 2 +- .../tags/block/incorrect_for_gold_tool.json | 2 +- .../tags/block/incorrect_for_iron_tool.json | 2 +- .../tags/block/incorrect_for_stone_tool.json | 2 +- .../tags/block/incorrect_for_wooden_tool.json | 2 +- .../block/incorrect_for_flint_multi_tool.json | 2 +- .../retold/tags/block/requires_steel_tool.json | 6 ++++++ 12 files changed, 39 insertions(+), 17 deletions(-) create mode 100644 src/main/resources/data/retold/tags/block/requires_steel_tool.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 456dcb6..d56d92a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ Each release should be readable in two passes: - The survival opening now begins with Sticks and Flint instead of punching logs. Leaves have an additional 20% chance to drop 1–2 Sticks, increasing by five percentage points per Fortune level; Dead Bushes drop 2–4 Sticks, while living Bush, Firefly Bush, Rose Bush, and Sweet Berry Bush blocks have a 10% chance to drop one. Shears and Silk Touch preserve the relevant blocks without extra Sticks. Logs require a suitable tool, the 2x2 Flint Multi-tool harvests the first wood, exposed Copper, and soft early stone, and vanilla Wooden and Stone tool recipes no longer bypass the material ladder. Copper generation now makes six vein attempts per chunk instead of sixteen while preserving normal vein sizes, reducing cave-wall clutter without making each discovery unrewarding. Copper Pickaxes can harvest normal Stone for Cobblestone, but do so at 25% speed until Iron makes ordinary mining practical. - Campfires are now crafted from three Sticks and three Logs without Coal or Flint and begin unlit immediately when placed, without briefly flashing their lit appearance. Using a bare Flint lights one and consumes that Flint in Survival, while Flint and Steel retains its normal durability-based ignition. Clay Balls fire into Bricks on a Campfire; eight Bricks in a ring then craft the Brick Furnace, Retold's renamed Smoker. It keeps food cooking, makes Charcoal from burnable logs, and processes Raw Copper and both Copper ores so players can reach Copper before obtaining Cobblestone for a normal Furnace. -- Blast Furnaces now process Iron Ingots directly into Steel Ingots using any ordinary fuel. The Spear now follows Flint, Copper, Iron, Steel, and Diamond progression, with new Flint and Steel Spears using provisional Stone and Iron visuals. Steel provides a full Pickaxe, Axe, Shovel, Hoe, Sword, Spear, and armor tier between Iron and Diamond. Pre-Steel tools cannot harvest Deepslate-family blocks or Deepslate ores; Copper and Iron also break them painfully slowly. Steel unlocks full deep mining and deep Diamond Ore, while Obsidian and Ancient Debris remain locked to Diamond. +- Blast Furnaces now process Iron Ingots directly into Steel Ingots using any ordinary fuel. The Spear now follows Flint, Copper, Iron, Steel, and Diamond progression, with new Flint and Steel Spears using provisional Stone and Iron visuals. Steel provides a full Pickaxe, Axe, Shovel, Hoe, Sword, Spear, and armor tier between Iron and Diamond. Pre-Steel tools cannot harvest Deepslate-family blocks, Deepslate ores, or normal Diamond Ore; Copper and Iron also break Deepslate painfully slowly. Steel unlocks all Diamond Ore and full deep mining, while Obsidian and Ancient Debris remain locked to Diamond. - Alternative equipment acquisition now follows fixed world rules in single-player and multiplayer. Bonus chests provide one Flint Multi-tool instead of Wooden/Stone tools; safe Village smith chests stop at Copper equipment and at most two Iron Ingots. Smith equipment trades unlock Copper at Apprentice for 8–12 Emeralds, Iron at Expert for 24–32, and Diamond at Master for 48–64, with enchanted Diamond offers rarer than unenchanted ones. The Wandering Trader retains its rare enchanted Iron Pickaxe at an enchantment-adjusted price around 48 Emeralds. - Mending can no longer be newly generated by Librarian trades or random loot. Existing Mending items continue to function, and commands and Creative mode retain the enchantment. - Unenchanted Diamond tools and Spears now have only 64 durability, while unenchanted Diamond armor has leather-like 6x durability. Diamond Horse and Nautilus Armor now use 96 durability before enchanting and 528 afterward, and lose durability from real hits like other armor. Any enchantment—including a curse by itself—immediately restores full Diamond durability; removing every enchantment makes the item fragile again. A heavily damaged item stripped beyond that fragile limit retains one final use instead of becoming invalid immediately. diff --git a/docs/internal/design_implementation_status.md b/docs/internal/design_implementation_status.md index 1cc057a..ef3fc7b 100644 --- a/docs/internal/design_implementation_status.md +++ b/docs/internal/design_implementation_status.md @@ -166,7 +166,7 @@ Largest missing or partial design areas: | Wood cannot be obtained by hand | Implemented / needs in-game verification | A harvest check prevents logs from dropping unless the held item is a correct harvesting tool. Focused GameTest coverage verifies hand denial and Flint Multi-tool success; naturally verify block breaking, drops, Adventure mode, and common modded logs. | | Flint multi-tool | Implemented / needs in-game verification | The 2x2 two-Flint/one-Stick recipe, 48-durability combined axe/shovel/primitive Copper tool, repair tag, creative placement, language entry, and provisional vanilla-Flint model are implemented. Focused GameTests verify the recipe, durability, logs, normal Copper Ore, Tuff, and Stone denial. Natural survival pacing and visuals remain unverified. | | Reduced Copper generation | Implemented / needs fresh-world verification | Both `minecraft:ore_copper` and `minecraft:ore_copper_large` now make six placement attempts per chunk instead of sixteen, a 62.5% frequency reduction. Vanilla size-10 ordinary and size-20 Dripstone veins plus their height distribution are preserved. A focused registry-backed GameTest verifies both loaded overrides across three seeded origins spanning a chunk border; several fresh seeds, cave-wall exposure, and existing-versus-new chunk behavior still need natural verification. | -| Flint/copper/iron/steel/diamond tool progression | Partial / needs verification | Progression is implemented through Diamond: Wooden/Stone recipes are removed, Copper unlocks slow Stone harvesting, Deepslate-family blocks and ores require Steel or better, Spears follow Flint/Copper/Iron/Steel/Diamond, and unenchanted tagged Diamond tools/Spear use 64 durability while any enchantment restores their vanilla maximum. Removing every enchantment makes them fragile again. Focused tests cover the boundaries, Spear recipes/tags, and transitions. Netherite/Aenderite equipment and final balance remain incomplete. | +| Flint/copper/iron/steel/diamond tool progression | Partial / needs verification | Progression is implemented through Diamond: Wooden/Stone recipes are removed, Copper unlocks slow Stone harvesting, Deepslate-family blocks and every Diamond Ore require Steel or better, Spears follow Flint/Copper/Iron/Steel/Diamond, and unenchanted tagged Diamond tools/Spear use 64 durability while any enchantment restores their vanilla maximum. Removing every enchantment makes them fragile again. Focused tests cover the boundaries, Spear recipes/tags, and transitions. Netherite/Aenderite equipment and final balance remain incomplete. | | Campfire, Brick Furnace, Furnace, Blast Furnace, and parallel enchanting progression | Partial / needs verification | Campfires use a fuel-free three-Stick/three-Log recipe. Their initial placement state is unlit on both logical sides, avoiding the former client-visible lit-state flash. Bare Flint ignites one and is consumed in Survival; Flint and Steel retains normal durability use. Campfire cooking fires Clay Balls into Bricks, and eight Bricks craft the Smoker-backed Brick Furnace. The Brick and normal Furnace roles are implemented. Per the 2026-08-11 choice, a standard 100-tick blasting recipe converts one Iron Ingot to one Steel Ingot while accepting ordinary Blast Furnace fuels; Charcoal is valid but not mandatory or fixed 1:1. Blast Furnace construction remains vanilla. Enchanting follows the separate deterministic SGA system. | | Leather/copper/iron/steel/diamond armor progression | Partial / needs verification | Steel has its provisionally balanced four-piece set. Unenchanted Diamond player armor uses 6x durability (66/96/90/78), while any enchantment restores 33x durability and removing all enchantments restores fragility. Diamond Horse and Nautilus Armor now follow the BODY/Chestplate 96/528 durability transition and take wear from real hits; non-Diamond animal armor remains indestructible. All twelve Wolf, Horse, and Nautilus Armor items support the exact Chestplate enchantment set and use their material's enchantability value. Focused equipped-animal tests cover damage wear, Protection-family mitigation, Fire Protection burn duration, Thorns, Unbreaking, Mending, Binding, and Vanishing paths. Retold bridges protection into Wolf Armor's special absorbed-durability path, while Horse and Nautilus armor use vanilla health mitigation. Later Retold armor tiers remain incomplete. | | Diamond tools weak unless enchanted | Implemented / needs in-game verification | A narrow `ItemStack` hook delegates to `RetoldDiamondDurability`; all twelve enchantable Diamond items use fragile unenchanted durability and their full maximum while enchanted. Any enchantment qualifies, including a curse as the item's only enchantment. Stripping a heavily damaged item preserves its damage and leaves one final use rather than an invalid stack. Focused coverage enumerates the complete set, verifies ordinary-enchantment, curse-only, removal, and damaged-item transitions, and confirms Diamond Horse/Nautilus Armor wear on real hits. | diff --git a/docs/internal/retold_mod_system.md b/docs/internal/retold_mod_system.md index f7f38d3..227f733 100644 --- a/docs/internal/retold_mod_system.md +++ b/docs/internal/retold_mod_system.md @@ -138,8 +138,10 @@ order is dependency-aware: faction precedes territory, and territory precedes be `RetoldToolProgressionEvents` owns the non-data opening rules: logs require a correct held tool, the Copper Pickaxe receives a Stone-specific speed penalty, Copper and Iron Pickaxes receive the Steel-tier Deepslate penalty, and exact vanilla Wooden/Stone tool recipes are removed during recipe -JSON modification. Tool-material correctness tags deny Deepslate-family drops to every pre-Steel -material while allowing Steel and later tiers to harvest them. `RetoldLeafStickLootModifier`, +JSON modification. Tool-material correctness tags deny Deepslate-family and all Diamond Ore drops +to every pre-Steel material while allowing Steel and later tiers to harvest them. The broader +`retold:requires_steel_tool` harvest tag is separate from the Deepslate-only speed tag. +`RetoldLeafStickLootModifier`, registered through `RetoldLootModifiers`, gives every `minecraft:leaves` block a supplemental 20% roll for 1–2 Sticks, increasing five percentage points per Fortune level. It also normalizes Dead Bushes to 2–4 Sticks and gives tagged living diff --git a/docs/internal/tool_armor_ore_progression.md b/docs/internal/tool_armor_ore_progression.md index 2679c08..8ec587d 100644 --- a/docs/internal/tool_armor_ore_progression.md +++ b/docs/internal/tool_armor_ore_progression.md @@ -327,12 +327,13 @@ Steel is the tier that unlocks **Deepslate** harvesting and opens the deepest Ov Copper and Iron Pickaxes break Deepslate-family blocks at 25% of their otherwise calculated speed but receive no drops. Wooden, Stone, Gold, Copper, Iron, and Flint tools all treat the data-driven -Steel-tier list as incorrect for drops. That list contains natural Deepslate, its construction -variants, and Deepslate ores. Steel mines and harvests them at its full speed, can harvest Deepslate -Diamond Ore, and still cannot harvest Obsidian, preserving Diamond's next access step. Diamond and -Netherite retain Deepslate harvesting after Steel. +Steel-required list as incorrect for drops. That list contains the Deepslate tier—natural +Deepslate, its construction variants, and Deepslate ores—plus normal Diamond Ore. Steel mines and +harvests Deepslate at full speed and is the first tier that can harvest either Diamond Ore variant. +It still cannot harvest Obsidian, preserving Diamond's next access step. Diamond and Netherite +retain Steel-unlocked harvesting. -This hard-gates deep Diamond access behind Steel. +This hard-gates all mined Diamond access behind Steel. Keep vanilla Diamond generation initially; let geological access provide the progression gate. @@ -555,7 +556,7 @@ Copper rate again only from concrete natural-world results. - Copper Pickaxe can mine Stone and obtain Cobblestone, but does so slowly. - Iron makes Stone mining practical. - Steel is produced by blasting Iron Ingots; Charcoal is an ordinary valid fuel rather than a required second ingredient. -- Pre-Steel tools cannot harvest Deepslate-family blocks or ores; Steel unlocks them and thereby opens deep Diamond progression. +- Pre-Steel tools cannot harvest Deepslate-family blocks, Deepslate ores, or normal Diamond Ore; Steel unlocks both Diamond Ore variants. - Ancient Debris remains in the Diamond harvest tier. - Copper and Steel receive full tool and armor sets. - Standard tool families follow the same tier ladder from Copper onward. diff --git a/src/main/java/cz/xefensor/retold/progression/RetoldToolProgressionGameTests.java b/src/main/java/cz/xefensor/retold/progression/RetoldToolProgressionGameTests.java index b0ba945..7e69271 100644 --- a/src/main/java/cz/xefensor/retold/progression/RetoldToolProgressionGameTests.java +++ b/src/main/java/cz/xefensor/retold/progression/RetoldToolProgressionGameTests.java @@ -715,6 +715,13 @@ private static void harvestRulesEnforceMaterialLadder( ), "Iron must not harvest constructed Deepslate variants" ); + helper.assertFalse( + Items.IRON_PICKAXE.getDefaultInstance() + .isCorrectToolForDrops( + Blocks.DIAMOND_ORE.defaultBlockState() + ), + "Iron must not harvest normal Diamond Ore" + ); ItemStack steelPickaxe = new ItemStack( RetoldBlocks.STEEL_PICKAXE.get() @@ -742,7 +749,13 @@ private static void harvestRulesEnforceMaterialLadder( steelPickaxe.isCorrectToolForDrops( Blocks.DEEPSLATE_DIAMOND_ORE.defaultBlockState() ), - "Steel must harvest deep Diamond ore" + "Steel must harvest Deepslate Diamond Ore" + ); + helper.assertTrue( + steelPickaxe.isCorrectToolForDrops( + Blocks.DIAMOND_ORE.defaultBlockState() + ), + "Steel must harvest normal Diamond Ore" ); helper.assertTrue( Items.DIAMOND_PICKAXE.getDefaultInstance() diff --git a/src/main/resources/data/minecraft/tags/block/incorrect_for_copper_tool.json b/src/main/resources/data/minecraft/tags/block/incorrect_for_copper_tool.json index 1dba507..e5f3dc5 100644 --- a/src/main/resources/data/minecraft/tags/block/incorrect_for_copper_tool.json +++ b/src/main/resources/data/minecraft/tags/block/incorrect_for_copper_tool.json @@ -1,6 +1,6 @@ { "replace": false, "values": [ - "#retold:steel_tier_blocks" + "#retold:requires_steel_tool" ] } diff --git a/src/main/resources/data/minecraft/tags/block/incorrect_for_gold_tool.json b/src/main/resources/data/minecraft/tags/block/incorrect_for_gold_tool.json index 1dba507..e5f3dc5 100644 --- a/src/main/resources/data/minecraft/tags/block/incorrect_for_gold_tool.json +++ b/src/main/resources/data/minecraft/tags/block/incorrect_for_gold_tool.json @@ -1,6 +1,6 @@ { "replace": false, "values": [ - "#retold:steel_tier_blocks" + "#retold:requires_steel_tool" ] } diff --git a/src/main/resources/data/minecraft/tags/block/incorrect_for_iron_tool.json b/src/main/resources/data/minecraft/tags/block/incorrect_for_iron_tool.json index 1dba507..e5f3dc5 100644 --- a/src/main/resources/data/minecraft/tags/block/incorrect_for_iron_tool.json +++ b/src/main/resources/data/minecraft/tags/block/incorrect_for_iron_tool.json @@ -1,6 +1,6 @@ { "replace": false, "values": [ - "#retold:steel_tier_blocks" + "#retold:requires_steel_tool" ] } diff --git a/src/main/resources/data/minecraft/tags/block/incorrect_for_stone_tool.json b/src/main/resources/data/minecraft/tags/block/incorrect_for_stone_tool.json index 1dba507..e5f3dc5 100644 --- a/src/main/resources/data/minecraft/tags/block/incorrect_for_stone_tool.json +++ b/src/main/resources/data/minecraft/tags/block/incorrect_for_stone_tool.json @@ -1,6 +1,6 @@ { "replace": false, "values": [ - "#retold:steel_tier_blocks" + "#retold:requires_steel_tool" ] } diff --git a/src/main/resources/data/minecraft/tags/block/incorrect_for_wooden_tool.json b/src/main/resources/data/minecraft/tags/block/incorrect_for_wooden_tool.json index 1dba507..e5f3dc5 100644 --- a/src/main/resources/data/minecraft/tags/block/incorrect_for_wooden_tool.json +++ b/src/main/resources/data/minecraft/tags/block/incorrect_for_wooden_tool.json @@ -1,6 +1,6 @@ { "replace": false, "values": [ - "#retold:steel_tier_blocks" + "#retold:requires_steel_tool" ] } diff --git a/src/main/resources/data/retold/tags/block/incorrect_for_flint_multi_tool.json b/src/main/resources/data/retold/tags/block/incorrect_for_flint_multi_tool.json index e756ff1..163affe 100644 --- a/src/main/resources/data/retold/tags/block/incorrect_for_flint_multi_tool.json +++ b/src/main/resources/data/retold/tags/block/incorrect_for_flint_multi_tool.json @@ -1,6 +1,6 @@ { "values": [ - "#retold:steel_tier_blocks", + "#retold:requires_steel_tool", "#minecraft:needs_iron_tool", "#minecraft:needs_diamond_tool" ] diff --git a/src/main/resources/data/retold/tags/block/requires_steel_tool.json b/src/main/resources/data/retold/tags/block/requires_steel_tool.json new file mode 100644 index 0000000..5a6f2af --- /dev/null +++ b/src/main/resources/data/retold/tags/block/requires_steel_tool.json @@ -0,0 +1,6 @@ +{ + "values": [ + "#retold:steel_tier_blocks", + "minecraft:diamond_ore" + ] +} From 3bbba3fd35dab9343d23ddf9e6a2aeceb71bf0ac Mon Sep 17 00:00:00 2001 From: xefensor Date: Wed, 12 Aug 2026 22:36:32 +0200 Subject: [PATCH 10/11] Retain provisional steel balance --- docs/internal/design_implementation_status.md | 2 +- docs/internal/tool_armor_ore_progression.md | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/internal/design_implementation_status.md b/docs/internal/design_implementation_status.md index ef3fc7b..5b2c68d 100644 --- a/docs/internal/design_implementation_status.md +++ b/docs/internal/design_implementation_status.md @@ -166,7 +166,7 @@ Largest missing or partial design areas: | Wood cannot be obtained by hand | Implemented / needs in-game verification | A harvest check prevents logs from dropping unless the held item is a correct harvesting tool. Focused GameTest coverage verifies hand denial and Flint Multi-tool success; naturally verify block breaking, drops, Adventure mode, and common modded logs. | | Flint multi-tool | Implemented / needs in-game verification | The 2x2 two-Flint/one-Stick recipe, 48-durability combined axe/shovel/primitive Copper tool, repair tag, creative placement, language entry, and provisional vanilla-Flint model are implemented. Focused GameTests verify the recipe, durability, logs, normal Copper Ore, Tuff, and Stone denial. Natural survival pacing and visuals remain unverified. | | Reduced Copper generation | Implemented / needs fresh-world verification | Both `minecraft:ore_copper` and `minecraft:ore_copper_large` now make six placement attempts per chunk instead of sixteen, a 62.5% frequency reduction. Vanilla size-10 ordinary and size-20 Dripstone veins plus their height distribution are preserved. A focused registry-backed GameTest verifies both loaded overrides across three seeded origins spanning a chunk border; several fresh seeds, cave-wall exposure, and existing-versus-new chunk behavior still need natural verification. | -| Flint/copper/iron/steel/diamond tool progression | Partial / needs verification | Progression is implemented through Diamond: Wooden/Stone recipes are removed, Copper unlocks slow Stone harvesting, Deepslate-family blocks and every Diamond Ore require Steel or better, Spears follow Flint/Copper/Iron/Steel/Diamond, and unenchanted tagged Diamond tools/Spear use 64 durability while any enchantment restores their vanilla maximum. Removing every enchantment makes them fragile again. Focused tests cover the boundaries, Spear recipes/tags, and transitions. Netherite/Aenderite equipment and final balance remain incomplete. | +| Flint/copper/iron/steel/diamond tool progression | Partial / needs verification | Progression is implemented through Diamond: Wooden/Stone recipes are removed, Copper unlocks slow Stone harvesting, Deepslate-family blocks and every Diamond Ore require Steel or better, Spears follow Flint/Copper/Iron/Steel/Diamond, and unenchanted tagged Diamond tools/Spear use 64 durability while any enchantment restores their vanilla maximum. Removing every enchantment makes them fragile again. The current provisional Steel values remain the working baseline until natural playtesting provides evidence for tuning. Focused tests cover the boundaries, Spear recipes/tags, and transitions. Netherite/Aenderite equipment remains incomplete. | | Campfire, Brick Furnace, Furnace, Blast Furnace, and parallel enchanting progression | Partial / needs verification | Campfires use a fuel-free three-Stick/three-Log recipe. Their initial placement state is unlit on both logical sides, avoiding the former client-visible lit-state flash. Bare Flint ignites one and is consumed in Survival; Flint and Steel retains normal durability use. Campfire cooking fires Clay Balls into Bricks, and eight Bricks craft the Smoker-backed Brick Furnace. The Brick and normal Furnace roles are implemented. Per the 2026-08-11 choice, a standard 100-tick blasting recipe converts one Iron Ingot to one Steel Ingot while accepting ordinary Blast Furnace fuels; Charcoal is valid but not mandatory or fixed 1:1. Blast Furnace construction remains vanilla. Enchanting follows the separate deterministic SGA system. | | Leather/copper/iron/steel/diamond armor progression | Partial / needs verification | Steel has its provisionally balanced four-piece set. Unenchanted Diamond player armor uses 6x durability (66/96/90/78), while any enchantment restores 33x durability and removing all enchantments restores fragility. Diamond Horse and Nautilus Armor now follow the BODY/Chestplate 96/528 durability transition and take wear from real hits; non-Diamond animal armor remains indestructible. All twelve Wolf, Horse, and Nautilus Armor items support the exact Chestplate enchantment set and use their material's enchantability value. Focused equipped-animal tests cover damage wear, Protection-family mitigation, Fire Protection burn duration, Thorns, Unbreaking, Mending, Binding, and Vanishing paths. Retold bridges protection into Wolf Armor's special absorbed-durability path, while Horse and Nautilus armor use vanilla health mitigation. Later Retold armor tiers remain incomplete. | | Diamond tools weak unless enchanted | Implemented / needs in-game verification | A narrow `ItemStack` hook delegates to `RetoldDiamondDurability`; all twelve enchantable Diamond items use fragile unenchanted durability and their full maximum while enchanted. Any enchantment qualifies, including a curse as the item's only enchantment. Stripping a heavily damaged item preserves its damage and leaves one final use rather than an invalid stack. Focused coverage enumerates the complete set, verifies ordinary-enchantment, curse-only, removal, and damaged-item transitions, and confirms Diamond Horse/Nautilus Armor wear on real hits. | diff --git a/docs/internal/tool_armor_ore_progression.md b/docs/internal/tool_armor_ore_progression.md index 8ec587d..c8db60d 100644 --- a/docs/internal/tool_armor_ore_progression.md +++ b/docs/internal/tool_armor_ore_progression.md @@ -321,6 +321,10 @@ and defenses of 3 Helmet, 7 Chestplate, 6 Leggings, and 3 Boots. Until a Steel a approved, inventory and equipped models deliberately reference vanilla Iron visuals without copying or modifying Minecraft textures. +These current Steel tool and armor values are the retained working baseline. Do not change them +pre-emptively; tune them only from concrete natural-play results comparing Iron, Steel, and +enchanted Diamond. + ### Steel mining identity Steel is the tier that unlocks **Deepslate** harvesting and opens the deepest Overworld geology. @@ -572,8 +576,8 @@ Copper rate again only from concrete natural-world results. ## Still Undecided -- final tool mining speeds and durability per tier beyond the provisional Flint, Copper, Steel, and unenchanted Diamond values -- final armor/combat stats beyond the provisional Steel and unenchanted Diamond values +- natural-play validation and any evidence-based tuning of the retained provisional Flint, Copper, Steel, and unenchanted Diamond tool values +- natural-play validation and any evidence-based tuning of the retained provisional Steel and unenchanted Diamond armor/combat values - exact block/tag harvest lists beyond the implemented Flint and Steel-tier opening boundaries - exact Aenderite crafting/upgrading method and special abilities - whether later nonstandard tools/weapons follow different material rules after the future combat/tool audit From 709686ade830bca32d17267d307c10f611a9c467 Mon Sep 17 00:00:00 2001 From: xefensor Date: Wed, 12 Aug 2026 22:40:46 +0200 Subject: [PATCH 11/11] Retain flint harvest baseline --- docs/internal/design_implementation_status.md | 2 +- docs/internal/tool_armor_ore_progression.md | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/internal/design_implementation_status.md b/docs/internal/design_implementation_status.md index 5b2c68d..5c0b9c8 100644 --- a/docs/internal/design_implementation_status.md +++ b/docs/internal/design_implementation_status.md @@ -164,7 +164,7 @@ Largest missing or partial design areas: | --- | --- | --- | | Leaves and bushes provide opening Sticks | Implemented / needs in-game verification | Every block in `minecraft:leaves` receives an additional 20% chance for 1–2 Sticks, with +5 percentage points per Fortune level. Dead Bushes drop 2–4, while Bush, Firefly Bush, Rose Bush, and Sweet Berry Bush receive a 10% one-Stick roll. Shears and Silk Touch are excluded. A focused real-loot-table GameTest samples the distributions and harvest exclusions; natural decay, explosions, modded leaves, bush farming, and first-spawn pacing remain to be verified in-game. | | Wood cannot be obtained by hand | Implemented / needs in-game verification | A harvest check prevents logs from dropping unless the held item is a correct harvesting tool. Focused GameTest coverage verifies hand denial and Flint Multi-tool success; naturally verify block breaking, drops, Adventure mode, and common modded logs. | -| Flint multi-tool | Implemented / needs in-game verification | The 2x2 two-Flint/one-Stick recipe, 48-durability combined axe/shovel/primitive Copper tool, repair tag, creative placement, language entry, and provisional vanilla-Flint model are implemented. Focused GameTests verify the recipe, durability, logs, normal Copper Ore, Tuff, and Stone denial. Natural survival pacing and visuals remain unverified. | +| Flint multi-tool | Implemented / needs in-game verification | The 2x2 two-Flint/one-Stick recipe, 48-durability combined axe/shovel/primitive Copper tool, repair tag, creative placement, language entry, and provisional vanilla-Flint model are implemented. Its retained harvest baseline combines axe/shovel blocks with normal Copper Ore, Sandstone variants, Tuff, and Calcite while denying Stone and Deepslate Copper Ore. Focused GameTests verify the recipe, durability, representative allowed blocks, and Stone denial. Natural survival pacing, full-list feel, and visuals remain unverified. | | Reduced Copper generation | Implemented / needs fresh-world verification | Both `minecraft:ore_copper` and `minecraft:ore_copper_large` now make six placement attempts per chunk instead of sixteen, a 62.5% frequency reduction. Vanilla size-10 ordinary and size-20 Dripstone veins plus their height distribution are preserved. A focused registry-backed GameTest verifies both loaded overrides across three seeded origins spanning a chunk border; several fresh seeds, cave-wall exposure, and existing-versus-new chunk behavior still need natural verification. | | Flint/copper/iron/steel/diamond tool progression | Partial / needs verification | Progression is implemented through Diamond: Wooden/Stone recipes are removed, Copper unlocks slow Stone harvesting, Deepslate-family blocks and every Diamond Ore require Steel or better, Spears follow Flint/Copper/Iron/Steel/Diamond, and unenchanted tagged Diamond tools/Spear use 64 durability while any enchantment restores their vanilla maximum. Removing every enchantment makes them fragile again. The current provisional Steel values remain the working baseline until natural playtesting provides evidence for tuning. Focused tests cover the boundaries, Spear recipes/tags, and transitions. Netherite/Aenderite equipment remains incomplete. | | Campfire, Brick Furnace, Furnace, Blast Furnace, and parallel enchanting progression | Partial / needs verification | Campfires use a fuel-free three-Stick/three-Log recipe. Their initial placement state is unlit on both logical sides, avoiding the former client-visible lit-state flash. Bare Flint ignites one and is consumed in Survival; Flint and Steel retains normal durability use. Campfire cooking fires Clay Balls into Bricks, and eight Bricks craft the Smoker-backed Brick Furnace. The Brick and normal Furnace roles are implemented. Per the 2026-08-11 choice, a standard 100-tick blasting recipe converts one Iron Ingot to one Steel Ingot while accepting ordinary Blast Furnace fuels; Charcoal is valid but not mandatory or fixed 1:1. Blast Furnace construction remains vanilla. Enchanting follows the separate deterministic SGA system. | diff --git a/docs/internal/tool_armor_ore_progression.md b/docs/internal/tool_armor_ore_progression.md index c8db60d..42c9c7c 100644 --- a/docs/internal/tool_armor_ore_progression.md +++ b/docs/internal/tool_armor_ore_progression.md @@ -188,7 +188,8 @@ The first implemented balance uses 48 durability, mining speed 2.0, attack damag speed -2.8. Its data-driven mining list combines normal axe and shovel blocks with ordinary Copper Ore, Sandstone variants, Tuff, and Calcite. It cannot harvest normal Stone, Deepslate Copper Ore, or blocks that require Iron or Diamond. These values and the exact soft-block list are provisional -until the natural opening loop is playtested. +until the natural opening loop is playtested. This current list is the retained working baseline; +do not add or remove blocks without concrete survival-play evidence. Once the player can obtain logs: @@ -578,6 +579,6 @@ Copper rate again only from concrete natural-world results. - natural-play validation and any evidence-based tuning of the retained provisional Flint, Copper, Steel, and unenchanted Diamond tool values - natural-play validation and any evidence-based tuning of the retained provisional Steel and unenchanted Diamond armor/combat values -- exact block/tag harvest lists beyond the implemented Flint and Steel-tier opening boundaries +- natural-play validation and any evidence-based tuning of the retained Flint and Steel-tier harvest lists - exact Aenderite crafting/upgrading method and special abilities - whether later nonstandard tools/weapons follow different material rules after the future combat/tool audit